Run command when vim enters visual mode - triggers

I use a little script to trigger insert modes in order to change the line number color:
function! CursorLineNrColorInsert(mode)
" Insert mode: blue
if a:mode == "i"
highlight CursorLineNr ctermfg=4
highlight CursorLineNr guifg=#268bd2
" Replace mode: red
elseif a:mode == "r"
highlight CursorLineNr ctermfg=1
highlight CursorLineNr guifg=#dc322f
else
highlight CursorLineNr ctermfg=0
highlight CursorLineNr guifg=#073642
endif
endfunction
autocmd InsertEnter * call CursorLineNrColorInsert(v:insertmode)
autocmd InsertLeave * highlight CursorLineNr ctermfg=0
autocmd InsertLeave * highlight CursorLineNr guifg=#073642
That works pretty fine and changes my line number instantly when I enter any insert mode and reverts back to the original color in normal mode.
I would like to do the same for the visual mode:
function! CursorLineNrColorVisual(mode)
" Visual mode: orange
if mode()=~#"^[vV\<C-v>]"
highlight CursorLineNr ctermfg=9
highlight CursorLineNr guifg=#cb4b16
else
highlight CursorLineNr ctermfg=0
highlight CursorLineNr guifg=#073642
endif
endfunction
autocmd CursorMoved * call CursorLineNrColorVisual(mode())
Basically that works but not instantly since the function is triggered on CursorMoved. How could I fire CursorLineNrColorVisual() instantly as soon as I would activate any visual mode?

After spending some time in :help I ended with the following setup:
" Colorize line numbers in insert and visual modes
" ------------------------------------------------
function! SetCursorLineNrColorInsert(mode)
" Insert mode: blue
if a:mode == "i"
highlight CursorLineNr ctermfg=4 guifg=#268bd2
" Replace mode: red
elseif a:mode == "r"
highlight CursorLineNr ctermfg=1 guifg=#dc322f
endif
endfunction
function! SetCursorLineNrColorVisual()
set updatetime=0
" Visual mode: orange
highlight CursorLineNr cterm=none ctermfg=9 guifg=#cb4b16
endfunction
function! ResetCursorLineNrColor()
set updatetime=4000
highlight CursorLineNr cterm=none ctermfg=0 guifg=#073642
endfunction
vnoremap <silent> <expr> <SID>SetCursorLineNrColorVisual SetCursorLineNrColorVisual()
nnoremap <silent> <script> v v<SID>SetCursorLineNrColorVisual
nnoremap <silent> <script> V V<SID>SetCursorLineNrColorVisual
nnoremap <silent> <script> <C-v> <C-v><SID>SetCursorLineNrColorVisual
augroup CursorLineNrColorSwap
autocmd!
autocmd InsertEnter * call SetCursorLineNrColorInsert(v:insertmode)
autocmd InsertLeave * call ResetCursorLineNrColor()
autocmd CursorHold * call ResetCursorLineNrColor()
augroup END
In order to restore the color of line numbers after leaving the visual mode I had to do the following steps:
Remap relevant key bindings to call an "enter-visual-function"
While entering visual mode the function sets updatetime=0 for CursorHold events
Call a "leave-visual-function" by autocmd CursorHold
While leaving visual mode the function resets updatetime=4000 for CursorHold events

As romainl has pointed out, there are no events for entering / exiting visual mode. I'd do it like this:
function! CursorLineNrColorVisual()
...
return '' " Return nothing to make the map-expr a no-op.
endfunction
vnoremap <expr> <SID>CursorLineNrColorVisual CursorLineNrColorVisual()
nnoremap <script> v v<SID>CursorLineNrColorVisual
nnoremap <script> V V<SID>CursorLineNrColorVisual
nnoremap <script> <C-v> <C-v><SID>CursorLineNrColorVisual
Alternatively, you could try putting an expression (%{CursorLineNrColorVisual}) into 'statusline'; this gets evaluated pretty often.

[EDIT] Promptlines plugin uses this method :
Since the statusline is re-drawn eachtime a mode is changed, you can have a trigger each time a mode is changed by adding %{AnyName(mode())} in your statusline (it will not be displayed). Then, you can implement an AnyName function that will be able to filter the current mode.
As an example:
let &stl.='%{RedrawStatuslineColors(mode())}'
function! RedrawStatuslineColors(mode)
if a:mode == 'n'
call NormalHighlight()
elseif a:mode == 'i'
call InsertHighlight()
elseif a:mode == 'R'
call ReplaceHighlight()
elseif a:mode == 'v' || a:mode == 'V' || a:mode == '^V'
call VisualHighlight()
endif
endfunction
[EDIT 2] Itchyny suggested to use the others methods on this thread, to avoid performances issues: It's advised to cache the mode and finish the function (ie. RedrawStatuslineColors()) instantly.

Related

Remap `AltGr & someKey`

How do I remap e.g. AltGr + i?
I know how to remap other combinations like alt + i (!i::Send, test) or shift + i (+i::Send, test). But this doesn't work for AltGr.
I know how to map AltGr isolated: LControl & RAlt::Send, test works. But LControl & RAlt & i::Send, test doesn't work.
So, how do I go about it?
EDIT: SOLVED
This solution worked
From the post that OP linked:
Use a context sensitive #IF statement to check whether AltGr is held down, then create a standard one-button hotkey.
#user3419297's example:
LControl & RAlt:: AltGr := true ; assign the boolean value "true" to the variable 'AltGr''
LControl & RAlt Up:: AltGr := false
; The #If directive creates context-sensitive hotkeys and hotstrings
#If (AltGr) ; If this variable has the value "true"
a:: MsgBox AltGr+a
a & b:: MsgBox AltGr+a+b
b & a:: MsgBox AltGr+b+a
h & l:: Send Hello
i & e:: Run iexplore.exe
n & p:: Run notepad
w & p:: Run wordpad
#If ; turn off context sensitivity
So for OP's specific question:
#If (AltGr)
i::Send, test
#If
More info: Context Sensative #IF statements

Using wdContentControlCheckBox in Word 2016

I recorded a Word macro which inserts a checkbox. The checkbox gets inserted, but the text does not. Why?
fwiw I'm using Word 2016 on Windows 10.
Sub CheckBox()
'
' CheckBox Macro
'
'
Selection.Range.ContentControls.Add (wdContentControlCheckBox)
Selection.MoveRight Unit:=wdCharacter, Count:=2
Selection.TypeText Text:=" z"
End Sub
Macros from the Recorder are just a starting point. Here is your recording turned into a functioning macro:
Sub Checkbox()
With Selection
.Range.ContentControls.Add (wdContentControlCheckBox)
.MoveRight Unit:=wdCharacter, Count:=2
.Range.Text = " z"
End With
End Sub
Try it this way:
Sub CheckBox()
With Selection.Range
.Text = " z"
.Collapse wdCollapseStart
.ContentControls.Add wdContentControlCheckBox
End With
End Sub

I'm trying to change font color in One Note trough an autohotkey

Im using this code in the autohotkey converter because I would like to press for example:
'ctrl + alt + r' to change the font color
SetTitleMatchMode, RegEx ; match window titles by regular expressions
#IfWinActive - OneNote$ ; ------ only in windows with title ending with "- OneNote"
^!p::Send, !hfca!hfc{Down 7}{Right 4}{Enter}
^!r::Send, !hfcm^{PgDn}!r255{Tab}5{Tab}0{Enter} ; red (255, 0, 0)
^!b::Send, !hfcm^{PgDn}!r0{Tab}5{Tab}255{Enter} ; blue (0, 0, 255)
^!a::Send, !hfca ; automatic color (i.e. reset font color to "none")
#IfWinActive ; ------ end of section restricted to specific windows
I executed this code trough the .exe file but nothing happened

How to fix 'If statement' always going for 'else'

I have a very simple 'IfEqual' statement, that always goes to 'else'
I tried it with the 'If' statement, like 'If %GuiText1%=Var1' and 'If (GuiText1 = Var1)', but got the same result
Gui, Add, Button, x25 y8 cBlue vSA , Var1
Gui, Add, Button, x20 y8 cRed vSD , Var2
GuiControl, Hide, SD
Gui,Show
{
ControlGetText, GuiText1,, new.ahk //to get the button-text from the window
msgbox, %GuiText1% //to check if its the right variable
IfEqual, %GuiText1%, Var1
{
msgbox, 1
}
else
{
msgbox, 2
}
}
It always goes straigth to 'else'
Variable names in an expression are not enclosed in percent signs.
IfEqual, GuiText1, Var1
IfEqual is deprecated and not recommended for use in new scripts.
Use the If Statement instead:
If GuiText1 = Var1 ; traditional mode
or, even better
If (GuiText1 = "Var1") ; expressional mode

Using a hotstring and an hotkey at the same time

This question is related to How to set `underline` followed by a character to send another key.
I would like that _t produces T and t produces s. But using the following _t produces _s. Is there any way to fix it?
t::s
:*:_t::T
The Computer can not see the differency between a [hotstring t presses] and a [hotkey t presses] the only thing what you can do is to do if _ is pressed [disable the hotkey] and then [enable enother t hotkey that send the Shift+t=T if the t is pressed] you can do that with the [#if] commands
try this AHK code.
; [+ = Shift] [! = Alt] [^ = Ctrl] [# = Win]
#SingleInstance force
mode=1
:*:_::
send _
mode=0
modes=1
return
#if mode
t::s
#if
#if modes
t::
send +t
mode=1
modes=0
return
#if
note - If you change the code a little bit, you can then also use a Hotstring in the modes for example: :*:test???:: minus the Hotstring :*:_???::
How about
:*:_t::T
t::SendRaw s
or with hotstrings
:*:_t::T
:*R:t::s
Oleg's comment below makes sense, add ? to the option(s) of the hotstring(s)
adding other keys
:*:_t::T
:*R:t::s
:*:a::a
:*:b::b
:*:c::c
:*:d::d
:*:e::e
:*:f::f
:*:g::g
:*:h::h
:*:i::i
:*:j::j
:*:k::k
:*:l::l
:*:m::m
:*:n::n
:*:o::o
:*:p::p
:*:q::q
:*:r::r
:*:u::u
:*:v::v
:*:w::w
:*:x::x
:*:y::y
:*:z::z