neovim :imap but stay printing before to replace - neovim

I'm writing a mapping in neovim. Here is:
:imap abcd efgh
When I type 'abcd', it replaces by 'efgh'. This is the expected behavior.
But as typing 'abcd', it prints a, then replaces a by b, then replaces b by d and, finally when I type 'd', it prints efgh. My cursor never moves.
In other words I never see "abc" as a whole.
What I want is to see "abc" and then, when typing "d", the whole gets replaced by "efgh".
I kind of remember that, in vim-latexsuite, I had :call IMAP ("abcd", "efgh") which made the work.
Is it possible with nvim ?

Related

AHK and US-INT keyboard: Why are "dead" keys no longer swallowed?

I normally use the United States-International keyboard layout. This layout has several keys set as "dead" keys for diacritic marks - for example, pressing ^ is a dead key; it appears to do nothing until the next key is hit; if that key is one that the circumflex is an allowable diacritic, it replaces it with the marked key - that is, if I press ^ then a, I will get â - but if I press a key that it's not an allowed diacritic for, I will get the circumflex followed by the letter, e.g., ^ follows by h gives me ^h.
I wrote a AHK script that adds the diacriticalized characters for Esperanto (see below). It used to work "transparently" and matched the behavior described above. However, recently, the behavior seems to have changed: it no longer "swallows" the diacritic, and inserts a backspace before inserting the character desired.
In other words, if I type "The Esperanto character that sounds like English 'ch' is " and then type ^ then c, it replaces the space following "is" with the ĉ, and on the next keystroke, whatever it is, acts like I had hit ^ then that key.
Why? and How do I fix this?
#Hotstring ? C *
; Esperanto diacriticalized characters
::^c::ĉ
::^C::Ĉ
::^g::ĝ
::^G::Ĝ
::^h::ĥ
::^H::Ĥ
::^j::ĵ
::^J::Ĵ
::^s::ŝ
::^S::Ŝ
::~u::ŭ
::~U::Ŭ
Don't know if I maybe missed something simple with hotstrings, but I couldn't really make it work without trying to do some even further trickery.
I figured an InputHook(docs) implementation could work pretty well.
It might be overkill/stupid though, since it basically just creates a custom implementation for a hotstring. But well, at least it works.
key_map := { "c": "ĉ"
, "g": "ĝ"
, "h": "ĥ"
, "j": "ĵ"
, "s": "ŝ"
, "u": "ŭ" }
ih := InputHook("V")
ih.OnChar := Func("OnChar")
ih.Start()
OnChar(_, char)
{
if (StrLen(char) != 2 || SubStr(char, 1, 1) != "^" || !(key := diacriticalize(SubStr(char, 2))))
return
fObj := Func("SendReplacement").Bind(key)
SetTimer, % fObj, -0
}
diacriticalize(key)
{
global key_map
if key is upper
return Format("{:U}", key_map[key])
else
return key_map[key]
}
SendReplacement(key)
{
SendInput, % "{BS 2}" key
}
So what's happening?
First a map for the key replacements is defined.
Adding any extra dead key combinations for ^ will work just fine.
The input hook is created with only the V(docs) option.
This makes it so that it doesn't consume input while processing it.
Then, with .OnChar(docs) we define a function that runs every time the input receives a new character.
The functions always receives just one character, except when a dead key is used it'll receive e.g ^c.
This is why we check if the input length is two and why we use SubStr()(docs) to transform ^c to just c.
SubStr(char, 1, 1) != "^" also ensures that the pressed deadkey was ^, and not e.g ¨. Otherwise ¨c would produce ĉ.
Then in the user defined function diacriticalize() we return the corresponding diacriticalized key from the key_map (if possible). If the input key was in uppercase, return the diacriticalized key in uppercase as well.
If there is no matching key in the key_map, nothing is returned. Which makes the || !(key := ...) part do its trick to also return if the input key wasn't valid.
Then the timer(docs) trickery is done just to execute the replacement outside of the OnChar() function in another thread to avoid problems with send command running too early.
Basically the period -0 just means to run once immediately.
The function which the timer will is defined as a function object that has a parameter (the key) bound to it with .Bind()(docs).
OK, I’m not sure why it works this way, but I was able to get it working by turning off the automatic backspacing and manually adding my own. The revised AHK script is as follows:
#Hotstring ? C * B0
; Acts only as a supplement to a keyboard that (a) does not
; have these characters defined _and_ uses ^ and ~ as "dead"
; keys to apply accents.
::^c::{bs 2}ĉ
::^C::{bs 2}Ĉ
::^g::{bs 2}ĝ
::^G::{bs 2}Ĝ
::^h::{bs 2}ĥ
::^H::{bs 2}Ĥ
::^j::{bs 2}ĵ
::^J::{bs 2}Ĵ
::^s::{bs 2}ŝ
::^S::{bs 2}Ŝ
::~u::{bs 2}ŭ
::~U::{bs 2}Ŭ
::^::^
::~::~
The B0 in the #Hotstring directive turns off the automatic backspacing. With that option in effect in the original script, typing ^c would result in ^cĉ, so by inserting two backspaces before it ({bs 2}), I get rid of the extraneous ^c before inserting the ĉ.
The last two lines, replacing the caret and tilde with themselves, don’t have an obvious explanation for the reason that they're needed, but they ensure that the behavior is consistent with the standard deadkey usage, so that if I type ^spacec I get the expected ^c instead of an unexpected ĉ.

Xcode breakpoint shell command argument length

Trying to pass a large string to a shell script using a breakpoint in Xcode
let value = Array(repeating: "a", count: 1500).joined()
let string = "{\"key\": \"\(value)\"}"
Unfortunately, the string is being truncated. Is this limitation documented and can it be overcome?
It's been nearly a year since you asked this, and I'm not sure if it will solve your question, but I've recently had a similar problem so thought I'd share my solution.
I had two issues:
LLDB was truncating any arguments to my shell script (and string variables printed in the console using po foo) to 1023 characters. I believe this is the issue to which your question relates.
Xcode was incorrectly confusing a comma , in my string as a separator for multiple arguments (e.g. passing foo, bar, and baz as arguments to the script wouldn't work correctly if any of the variables contained a , as Xcode would try to create another argument).
So, firstly, the LLDB issue...
It seems that by default LLDB has a limit on the character length that it will print to the console (or pass to a shell script via a breakpoint argument) of around 1023 characters. You can easily change this to something larger by setting another breakpoint before the breakpoint that uses your variable and running (lldb) set set target.max-string-summary-length 10000 in the console. This can be a bit annoying so I created a ~/.lldbinit file and placed set set target.max-string-summary-length 10000 in there instead so I don't have to keep setting it in the console.
Secondly, the comma issue...
Inside the Edit breakpoint... menu that you provided a screenshot of above there is the option to not only provide a path to a script but to also provide arguments. I can see from your question that you provided the argument #string#. For my script, I was passing multiple arguments, which Xcode allows you to do using a comma separated list, e.g. #foo#, #bar#, #baz#. Each of these arguments was a string.
I noticed that sometimes one or more of these strings would truncate if they contained a comma: ,.
So the string:
{ "num_friends" : "7" }
would be passed to my script as expected. But the string:
{ "num_friends" : "7", "num_deleted_friends" : "1" }
would truncate and would be passed to my script as two separate arguments. It seems that Xcode would split any string with a , even when entered using #string#.
I validated this in my script by simply using something like:
for var in "$#"
do
echo "$var"
echo "===="
done
Where $# expands to contain each argument. From this I could see that #string# was being correctly passed to my script but separated as multiple arguments wherever there was a ,. So if #string# contained a comma my script would print:
#"{ \"num_friends\" : \"7\"
====
\"num_deleted_friends\" : \"1\" }"
instead of what I expected which was:
#"{ \"num_friends\" : \"7\", \"num_deleted_friends\" : \"1\" }"
So it seems like it might be a bug in how Xcode passes strings inside # expressions in the breakpoint editor window.
My crude solution has been to just replace any commas with another character and then replace them back again inside my script. There's probably a better way to do this but I don't require it for my needs.

Capture Send with Input

I have a script that I use to insert special characters and implement dead keys. The special characters are inserted with SendEvent. When a dead key is activated, the script runs Input, key, L1 and looks up the result in a table to find a composed character.
This works fine for real keypresses, but if I trigger a dead key and then cause a special character to be inserted with SendEvent, the Input call doesn't notice it. The special character is inserted verbatim and the next real keypress will go to the Input call.
How can I alter my script so that special characters inserted by the script will be captured by Input?
I am running a minimal script to demonstrate the issue:
SpecialCharacter(char) {
SendEvent %char%
}
DeadKey(combining) {
Input, key, L1
SendEvent %key%
SendEvent %combining%
}
^q::SpecialCharacter("a")
^w::DeadKey("b")
^ESC::Reload
The actual application will be more complex.
Actual output:
Ctrl-q: a
Ctrl-w, x: xb
Ctrl-w, Ctrl-q: no output
Ctrl-w, Ctrl-q, x: xb
Desired output:
Ctrl-w, Ctrl-q: ab
Ctrl-w, Ctrl-q, x: abx
I tried fiddling around with SendLevel/#InputLevel, but I don't think that those affect the behavior of the Input command.

ZX81 ‘BASIC’ peek function

I want to find the code of a character printed.
This is the code:
10 Print AT 2,2; "T"
20 Let C=Peek(Peek 16398+256*Peek 16399)
30 Print Peek(C)
It should just print the Code value of T.
I could later use:
40 Print Peek (Code C)
Or something.
But the 10-30 bit doesn't work. It always returns '0' -With different letters too: G,T 'black graphic' and M,
What am I doing wrong?
Will be used for collision detection.
jdehaan's right, printing the T without a trailing ; will move the cursor down to the next line after printing. (With ;, it's be one position to the right.)
To read the character you'd just written you'd have to move back a position again:
PRINT AT 2,2;"T";AT 2,2;
PRINT PEEK(PEEK 16398+PEEK 16399*256)
gives me 57, which is the character code for T.
According to this it is the right address to peek, but maybe the cursor is not at the right position? If I remember well (man, what are you doing with that old thing :-) ! ) the PRINT AT might move the cursor one position after the printed char (or one line under).

Vim: change formatting of variables in a script

I am using vim to edit a shell script (did not use the right coding standard). I need to change all of my variables from camel-hum-notation startTime to caps-and-underscore-notation START_TIME.
I do not want to change the way method names are represented.
I was thinking one way to do this would be to write a function and map it to a key. The function could do something like generating this on the command line:
s/<word under cursor>/<leave cursor here to type what to replace with>
I think that this function could be applyable to other situations which would be handy. Two questions:
Question 1: How would I go about creating that function.
I have created functions in vim before the biggest thing I am clueless about is how to capture movement. Ie if you press dw in vim it will delete the rest of a word. How do you capture that?
Also can you leave an uncompleted command on the vim command line?
Question 2: Got a better solution for me? How would you approach this task?
Use a plugin
Check the COERCION section at the bottom of the page:
http://www.vim.org/scripts/script.php?script_id=1545
Get the :s command to the command line
:nnoremap \c :%s/<C-r><C-w>/
<C-r><C-w> gets the word under the cursor to command-line
Change the word under the cursor with :s
:nnoremap \c lb:s/\%#<C-r><C-w>/\=toupper(substitute(submatch(0), '\<\#!\u', '_&', 'g'))/<Cr>
lb move right, then to beginning of the word. We need to do this to get
the cursor before the word we wish to change because we want to change only
the word under the cursor and the regex is anchored to the current cursor
position. The moving around needs to be done because b at the
start of a word moves to the start of the previous word.
\%# match the current cursor position
\= When the substitute string starts with "\=" the remainder is interpreted as an expression. :h sub-replace-\=
submatch(0) Whole match for the :s command we are dealing with
\< word boundary
\#! do not match the previous atom (this is to not match at the start of a
word. Without this, FooBar would be changed to _FOO_BAR)
& in replace expressions, this means the whole match
Change the word under the cursor, all matches in the file
:nnoremap \a :%s/<C-r><C-w>/\=toupper(substitute(submatch(0), '\<\#!\u', '_&', 'g'))/g<Cr>
See 3. for explanation.
Change the word under the cursor with normal mode commands
/\u<Cr> find next uppercase character
i_ insert an underscore.
nn Search the last searched string twice (two times because after exiting insert mode, you move back one character).
. Repeat the last change, in this case inserting the underscore.
Repeat nn. until all camelcases have an underscore added before them, that is, FooBarBaz has become Foo_Bar_Baz
gUiw uppercase current inner word
http://vim.wikia.com/wiki/Converting_variables_to_camelCase
I am not sure what you understand under 'capturing movements'. That
said, for a starter, I'd use something like this for the function:
fu! ChangeWord()
let l:the_word = expand('<cword>')
" Modify according to your rules
let l:new_var_name = toupper(l:the_word)
normal b
let l:col_b = col(".")
normal e
let l:col_e = col(".")
let l:line = getline(".")
let l:line = substitute(
\ l:line,
\ '^\(' . repeat('.', l:col_b-1) . '\)' . repeat('.', l:col_e - l:col_b+1),
\ '\1' . l:new_var_name,
\ '')
call setline(".", l:line)
endfu
As to leaving an uncompleted command on the vim command line, I think you're after
:map ,x :call ChangeWord(
which then can be invoked in normal mode by pressing ,x.
Update
After thinking about it, this following function is a bit shorter:
fu! ChangeWordUnderCursor()
let l:the_word = expand('<cword>')
"" Modify according to your rules
let l:new_var_name = '!' . toupper(l:the_word) . '!'
normal b
let l:col_b = col(".")
normal e
let l:col_e = col(".")
let l:line = getline(".")
exe 's/\%' . l:col_b . 'c.*\%' . (l:col_e+1) .'c/' . l:new_var_name . '/'
endfu