Creating a python comment string with only VIM commands - vim

I have a vim function:
function! Pycom(word)
let a:inserted_word = ' ' . a:word . ' '
let a:word_width = strlen(a:inserted_word)
let a:length_before = (118 - a:word_width) / 2
let a:hashes_before = repeat('#', a:length_before)
let a:hashes_after = repeat('#', 118 - (a:word_width + a:length_before))
let a:hash_line = repeat('#', 118)
let a:word_line = '# '. a:hashes_before . a:inserted_word . a:hashes_after
:put =toupper(a:word_line)
endfunction
noremap <leader>pc :call Pycom('')<Left><Left>
that creates Python comments. The output is like so:
# ########################################### Hello World ############################################
How can I create a key mapping to place in my vimrc to create my comment string with only Vim commands? I need to do this because I use PyCharm and in Vim emulation mode it does not allow calling functions.

If just :function were missing, you could inline the individual commands into a long, unsightly command sequence. But it's unlikely that a Vim emulation will just omit functions; the problem is that Vimscript itself is tightly bound to Vim itself, and mostly just specified by the behavior by its sole implementation inside Vim. So I'd guess that strlen(), repeat(), and even :put ={expression} won't work in PyCharm, neither.
Most Vim emulations just offer basic :map commands. Without knowning anything about PyCharm, the following general approaches can be tried:
If the emulation offers the :! (or :{range}!) command to invoke external commands, you can implement the functionality in an external command, implemented in whatever programming language you prefer. (If the emulation doesn't offer the :{range}! command, you'd have to :write the buffer first and pass the filename and current location somehow to the external command.)
Some emulations also offer a non-standard command to invoke their own core editor functions (so you might be able to implement it with that) or even arbitrary custom code; for example, for a NodeJS-based editor, that could be JavaScript code.
In general, Vim emulations are quite limited and can only emulate basic vi features (though I've also seen custom re-implementations of some popular Vim plugins, like surround.vim).
Alternative
To get more of Vim's special capabilities into your IDE, use both concurrently; it is very easy to set up a external tool in your IDE that launches Vim with the current file (and position). Automatic reloading of changes (in Vim via :set autoread) allows you to edit source code in both concurrently.

Related

How do you execute a global command in a vimscript function?

How do I write a function that executes the :NERDTree commands? Note: I am using neovim but i'm assuming the vimscript syntax is the same
here is my code
nmap <expr> <C-n> Toggle()
func Toggle()
if g:open == 0
let g:open += 1
execute g:NERDTreeCWD
else
let g:open -= 1
execute g:NERDTreeClose
endfunc
The NERDTree commands are custom Ex commands, so you invoke them (interactively) via :NERDTreeCWD followed by Enter. In a Vimscript, you can drop the : prefix.
Maybe part of the confusion (also seen in the comments) arises from the fact that the NERDTree commands are implemented by global functions with the same name:
:verbose command NERDTreeCWD
Name Args Address Complete Definition
| NERDTreeCWD 0 call NERDTreeCWD()
So you could also bypass the custom function and call NERDTreeCWD() directly, but this would make you depend on implementation details of the plugin, and is therefore discouraged.
Implementing NERDTree toggling
Are you aware that the plugin already has a :NERDTreeToggle command?
Also, you don't need to define your own flag variable (g:open) - just reuse the one from the plugin (exposed via the g:NERDTree.IsOpen() function). Yes, this makes you depend on plugin details (but this looks like a public API, not internal implementation, so it should be far more stable) - it's still better than trying to reinvent the wheel. (Your global flag would have problems with multiple tab pages - each could have a NERDTree active or not.)

vim redirect output to quickfix

Is it possible to redirect an output of a command to the quick fix window?
The command I am running is
:!java %:r
and was hoping the output would go into the quickfix window
I would suggest one of two options: configure makeprg to run java like you want, or create a mapping or command to populate the quickfix list without changing anything else.
Option 1: Using makeprg and compiler plugins
I would generally set the makeprg option for this, as others have said. It's not a hack, that's exactly what the makeprg option is for.
The only problem is if you have another build script you want to run as well. A more general solution is to create a simple compiler plugin. For instance, somewhere on your runtimepath, you can create a file under compiler/java.vim and set it to something like this:
if exists("current_compiler")
finish
endif
let current_compiler = "java"
CompilerSet makeprg=java
Now when you're working with java, you can do :compiler java and then your makeprg will be set as desired in the current window. If you want to use it for all windows, use :compiler! java, with a bang. Not all compiler plugins set the makeprg option, but you can always reset it with :set makeprg&. Try :help write-compiler-plugin for more information.
Option 2: Create a command to do it
Alternatively, you can also use cexpr to populate the quickfix list. For instance:
:cexpr system('java ' . shellescape(expand('%:r')))
The expand is necessary to expand the '%:r' in an expression, and shellescape escapes it so it can be used as an argument to a shell command. Then the string 'java ' is prepended to the escaped path and the result is invoked as a shell command by system. The output from this command is used to load the quickfix list.
The nice thing about this is that it doesn't change makeprg or any other settings, but still lets you easily populate the quickfix list. Of course, you'll probably want to map this or define a custom command for it.
Please note that the quickfix window is for specific output (e.g. of compiler or syntax checker tools) which includes references (i.e. line and column numbers) to the current buffer. There's a lot of infrastructure around this: 'makeprg', 'errorformat', etc., usually bundled into a compiler plugin.
Though you can redirect arbitrary output into the quickfix window, it provides little benefit (and has the downside of clobbering 'makeprg') over reading the output of an external program into a new scratch buffer, e.g. like this:
:new|0read !java #:r
Try this:
set makeprg=java
make %:r
It's a bit of hack, and of course assumes you aren't already using makeprg for your actual build script.
I mapped leader + j + r to run my java code and display it in the quickfix window by doing
map <leader>jr :set makeprg=java <CR>:make %:r<CR>:copen<CR>

vim run make through screen

Due to some complicated environmental variables required, I have chosen to run Make through GNU screen. Using the screen vim plugin, I have the following setup in my .vimrc:
map <Leader>mm :call ScreenShellSend("cd ".expand("%:p:h")." && make 2>&1 | tee /path/to/errorfile") <CR>
Roughly translated, this will run make in the current working directory through an existing screen session with all of the required environment variables preset. I can then see the output of that command in a separate terminal window.
My question is, assuming I output the results of make to a text file, how do I tell automate the vim make process to:
A.) set make to use a vimscript function, i.e. call SreenShellSend() instead of an external program.
B.) set errorfile to /path/to/errorfile
Unfortunately, you cannot set 'makeprg' to a Vim function or command, it has to be a shell program. (I wish for an enhancement that treats commands starting with a colon as Vim commands, similar to the :help exception in 'keywordprg', but haven't come around to implementing this.)
There are workarounds, though. One is to use vim --remote-send as 'makeprg' and use this other temporary Vim instance to call back into the original Vim. What I do though is overriding the :make command through the cmdalias.vim plugin for those buffers. That alias then simply :calls my function.
Once you're able to invoke a Vim function, setting the 'errorfile' is just a matter of putting a function wrapper around ScreenShellSend() and setting it in there.

How to start Erlang shell from inside Vim

I want to use Vim as the editor for my Erlang coding.
I managed to install the plugin for Erlang in vim, and I want to know if it is possible to
compile the current buffer inside vim? In Emacs for example you can start Erlang shell using Ctrl C + Ctrl L
key combination. So is there a alternative in Vim to start the Erlang shell and then compile the current buffer?
For a quick shell command from inside Vim, use :!command -a -b arg1 (e.g. :!ls -l, :!erl %).
But Emacs is not Vim, they have different ideas behind both. Vim is just a text editor with programming extensions, it's not a place for terminal inside (just as for tetris and M-x doctor).
Vim maintainers refuse to add a full-blown terminal implementation into Vim itself (for more details, see :help shell-window ).
If you still want an in-buffer shell, you can take a look at ConqueTerm , but it does not work seamlessly. I tried it, but prefer using tmux / screen to split my console's screen estate into windows.
I also use the same vimerl plugin for erlang development in vim. However, I had to make a small change to it to make some improvements to the way it compiles for checking.
Once I'd made these changes, writing the file (e.g. with :w) caused vimerl to compile that source file and put the warnings/errors in the quickfix list (exactly the same way that :make would do if you had a Makefile in place).
FWIW, I also have the following configuration in my vimrc:
let g:erlangHighlightErrors = 1
let g:erlangHighlightBif = 1
let g:erlangCompletionDisplayDoc = 1
let g:erlangWranglerPath = "/usr/local/share/wrangler"
let g:erlangRefactoring = 1

Calling into a shared object on a key-sequence from vi/Vim

I have a shared library (in binary form; I have the source) that I use to invert/cycle between symbols in source files in Visual Studio.
I would like to be able to use the same functionality in vi and/or Vim.
Specifically, what I'd like to do is the following scenario:
the cursor is on a word
I press a key-sequence, e.g. CTRL-I
vi/Vim works out the whole of the word I'm on
vi/Vim invokes my shared library, passing the word, and receiving the invert/cycle replacement
vi/Wim replaces the original word with the new word
I don't have any clue if/how to get vi/Vim to do this, and I'm not having any luck searching.
Any advice gratefully received ...
Try
inoremap <C-i> <esc>"hciw<C-R>=libcall('path/to/your.dll', 'func', #h)<CR>
What it does:
create map for insert mode <Ctrl+i>
<esc> switch to normal mode "hciw move word under cursor into the register h
<C-r>= insert into cursor position result of the next expression
libcall(...) calls function in the run-time library.
#h is the value of the 'h' register.
In case you want to use simple binary that can be ran from the command line you can use
inoremap <C-i> <esc>"hciw<C-R>=substitute(system('mybin --word='.#h), "\n", '', 'g')<CR>
I don't know how to call a shared library from normal vim scripts, but if you can create a python wrapper for your library and you're using vim version greateri than 7, you might do it calling a python script within vim.
First of all, check if you have python support enabled: type
:version
inside vim to list the available features; if it has python support, you should see a '+python' somewhere (a '-python' otherwise). If you do not have python enabled, you may refer to this post to compile vim with python support.
Then, you could could map a key to call a python function with the word currently under the cursor:
python << EOF
import vim
import MySharedLibraryPythonBinding
def MyFunction():
# get word under cursor
x = vim.eval('expand ("<cword>")')
# get replacement
MySharedLibraryPythonBinding.GetReplacement(x)
# replace contents (you'll need some work here...)
vim.current.line = "add something sensible here..."
EOF
nmap <F3> :py MyFunction( expand("<cword>") )<CR>
This is not of course a fully working solution, but I hope it will put you on the good route.
There are many ways to do it (:h expand(), ...). One of them is the following)
:nnoremap triggerkeysequence ciw<c-r>=libcall('path/to/your.dll', 'your_function',#")<cr>
BTW: <c-i> is <tab>, are you sure you want to override the action on this key?

Resources