I'm trying to use the following vim function to run my sas on windows, but I always got error message saying the argument for system is invalid.
Could some vim expert help me out?
myy sas is installed in:
C:\Program Files\SAS\SAS\9.1\sas.exe
function! RunSASonCurrentFile()
" Make sure this is a SAS program file (ends with .sas) so that
" we don't run SAS on a log file or similar.
:let checkSASpgm=match(expand("%"),"\.sas")
" If we did not match .sas in the file name, end this function with
" a warning msg
if checkSASpgm==-1
:echo "*** Current file is not a SAS program. SAS run has been canceled."
:return
endif
" Ask user if we want to run SAS so we don't accidentally run it.
:let l:answer = input("Run SAS? Y/N ")
:if (l:answer == "Y" || l:answer == "y")
" If file has been modified, save it before running
if exists(&modified)
:echo "*** Saving modified file before SAS run..."
:w
endif
" Run SAS on path/file name (modify to your location of sas)
:echo "*** Running SAS..."
"let returntxt = system("/usr/local/bin/sas -nodms " . shellescape(expand("%:p")))
" The following may work for your Windows system. Comment the line above and uncomment
" the two lines below and make them one long line.
let returntxt = system("\"" . shellescape("C:\\Program\ Files\\SAS\\SAS\9.1\\sas.exe")
". "\ -nosplash" . "\ -sysin" . "\ " . shellescape(expand("%:p")) . "\"")
" Shows the return messages from the SAS commandline (may be useful
" if no log produced)
:echo "*** SAS commandline: " . returntxt
:call LoadSASLogList()
:else
:echo "SAS Run cancelled."
" endif for the Run SAS? check
:endif
endfunction
Vim patch 7.3.443 changed the behavior of the shell escaping (which continues to be a trouble spot, due to the arcane Windows shell escaping rules). Whereas beforehand, one had to enclose the entire command line in double quotes if it contained a (itself quoted) executable with spaces in it, these now have to be removed. Try the following:
let returntxt = system(shellescape('C:\Program Files\SAS\SAS\9.1\sas.exe') . ' -nosplash -sysin ' . shellescape(expand('%:p')))
This also avoids some additional escaping by using single quoted strings.
If that's the exact text of your function, I think you're missing a second \ between SAS and 9.1 in the line let returntxt = system("\"" . shellescape("C:\\Program\ Files\\SAS\\SAS\9.1\\sas.exe").
Related
Is there a way to rename the terminal buffer? using :b to switch buffers, terminal buffers are often shown as !/usr/local/bin/fish and !/usr/local/bin/fish (1) which isn't very useful. Ideally It could auto rename itself, but I'm also okay with manually naming them (i.e. docker-compose up) after I start the job with in a terminal.
Here's a function I made for it. Disclaimer: I'm no Tim Pope
function! RenameTerminalBufferToCurrentCommand()
" unable to access $HISTFILE from vim, so change this variable to your history file
let l:historyFile = "~/.zsh_history"
let l:mostRecentCommand = system("tail -1 " . l:historyFile . " | cut -f2- -d\\;")
" i prepend "term" for easy buffer searching, but feel free to delete
let l:newFileName = "term " . fnameescape(trim(l:mostRecentCommand))
" the keepalt stops :file from creating an alternative file (alt files are
" annoying when buffer switching)
" :file renames the buffer
silent! execute "keepalt file " . l:newFileName
endfunction
tnoremap <Enter> <Enter><C-\><C-n>:call RenameTerminalBufferToCurrentCommand()<Enter>a
https://unix.stackexchange.com/questions/3497/how-to-change-the-name-of-a-vim-buffer
https://www.reddit.com/r/unix/comments/9u7le4/running_the_zsh_history_command_to_load_result/e928r7y/
https://www.reddit.com/r/vim/comments/7bcrkf/what_to_do_with_unlisted_buffers/
I am trying to write a vim function that conditionally changes the behavior of the enter key. I want the enter key to sometimes indent, other times behave "normally". By normally I mean that if a series of cases doesn't apply, act like the function/mapping doesn't exist. The trouble I'm running into is that I'm using <CR> as my trigger to invoke the function, and thus I'm not sure how to just say "oh, none of these cases apply, execute a <CR> as if this mapping was never defined."
As an example, consider this in my .vimrc, which indents the line if it starts with an a, otherwise triggers a carriage return. (My vimscript is very novice, so this function might not be correct, but I think the idea remains...)
function! SpecialEnter()
let line=getline(".")
if line =~ '\va*'
" at least one space then a valid indentation
normal! >>
else
" just do the regular thing
" echo "in else"
call feedkeys("\<CR>")
endif
endfunction
inoremap <CR> <Esc>:call SpecialEnter()<CR>
This is somewhat simplified from what I'm actually trying to do, but the concept is the same. I'm looking for a way to say "none of my if statements applied, act like this mapping doesn't exist". Is there a way to do this?
You need to give your mapping the <expr> flag. With this, the right hand side of your mapping is evaluated as an expression.
Here is an example taken from my config where I return different prompts for different commands:
cnoremap <expr> <CR> CCR()
" make list-like commands more intuitive
function! CCR()
let cmdline = getcmdline()
command! -bar Z silent set more|delcommand Z
if cmdline =~ '\v\C^(ls|files|buffers)'
" like :ls but prompts for a buffer command
return "\<CR>:b"
elseif cmdline =~ '\v\C/(#|nu|num|numb|numbe|number)$'
" like :g//# but prompts for a command
return "\<CR>:"
elseif cmdline =~ '\v\C^(dli|il)'
" like :dlist or :ilist but prompts for a count for :djump or :ijump
return "\<CR>:" . cmdline[0] . "j " . split(cmdline, " ")[1] . "\<S-Left>\<Left>"
elseif cmdline =~ '\v\C^(cli|lli)'
" like :clist or :llist but prompts for an error/location number
return "\<CR>:sil " . repeat(cmdline[0], 2) . "\<Space>"
elseif cmdline =~ '\C^old'
" like :oldfiles but prompts for an old file to edit
set nomore
return "\<CR>:Z|e #<"
elseif cmdline =~ '\C^changes'
" like :changes but prompts for a change to jump to
set nomore
return "\<CR>:Z|norm! g;\<S-Left>"
elseif cmdline =~ '\C^ju'
" like :jumps but prompts for a position to jump to
set nomore
return "\<CR>:Z|norm! \<C-o>\<S-Left>"
elseif cmdline =~ '\C^marks'
" like :marks but prompts for a mark to jump to
return "\<CR>:norm! `"
elseif cmdline =~ '\C^undol'
" like :undolist but prompts for a change to undo
return "\<CR>:u "
else
return "\<CR>"
endif
endfunction
In my vimrc I call Uncrustify by this command:
%!uncrustify -l CPP -c D:\uncrustify\default.cfg
After that on some code I get a Windows Fatal error:
But when I call uncrustify on the same code in the console using the -f option, there is no error.
How can I change my vimrc to avoid such errors in the future? What can invoke this error?
In order to integrate Uncrustify with Vim properly, add the following to your .vimrc:
" Restore cursor position, window position, and last search after running a
" command.
function! Preserve(command)
" Save the last search.
let search = #/
" Save the current cursor position.
let cursor_position = getpos('.')
" Save the current window position.
normal! H
let window_position = getpos('.')
call setpos('.', cursor_position)
" Execute the command.
execute a:command
" Restore the last search.
let #/ = search
" Restore the previous window position.
call setpos('.', window_position)
normal! zt
" Restore the previous cursor position.
call setpos('.', cursor_position)
endfunction
" Specify path to your Uncrustify configuration file.
let g:uncrustify_cfg_file_path =
\ shellescape(fnamemodify('~/.uncrustify.cfg', ':p'))
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction
Now you can either map this function (Uncrustify) to a combination of keys or you could do the convenient trick that I use. Create a file ~/.vim/after/ftplugin/cpp.vim where you can override any Vim settings particularly for C++ and add the following line there:
autocmd BufWritePre <buffer> :call Uncrustify('cpp')
This basically adds a pre-save hook. Now when you save the file with C++ code it will be automatically formatted by Uncrustify utilizing the configuration file you supplied earlier.
For example, the same could be done for Java: in ~/.vim/after/ftplugin/java.vim add:
autocmd BufWritePre <buffer> :call Uncrustify('java')
You got the point.
NOTE: Everything presented here is well-tested and used every day by me.
I have found the placing the following code into your .vimrc to be sufficient:
let g:uncrustifyCfgFile = '~/.uncrustify.cfg'
function! UncrustifyFunc(options) range
exec a:firstline.','.a:lastline.'!uncrustify '.a:options
\.' -c '.g:uncrustifyCfgFile.' -q -l '.&filetype
endfunction
command! -range=% UncrustifyRange <line1>,<line2>call UncrustifyFunc('--frag')
command! Uncrustify let s:save_cursor = getcurpos()
\| %call UncrustifyFunc('')
\| call setpos('.', s:save_cursor)
Note this does assume that you have "uncrustify" binary in your $PATH.
It also assumes your configure file is ~/.uncrustify.cfg however you can change that by modifiying the g:uncrustifyCfgFile variable.
To call run
:Uncrustify
It also works on ranges (which was what promoted me to make this function). Visual selection example:
:'<,'>UncrustifyRange
I have only tired it with C, CPP and JAVA (I assume others will work as well)
In addition to #Alexander Shukaev's answer, adding the following will perform a check for uncrustify config correctness and not auto format if error is detected:
let output = system('uncrustify -q -c ' . a:cfgfile)
if v:shell_error != 0
echo output
endif
return v:shell_error
endfunction
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
if CheckUncrustifyCfg(g:uncrustify_cfg_file_path)
echo "Config file" g:uncrustify_cfg_file_path "has errors"
echo "No formatting will be performed"
return
endif
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction
I'm using a vim plugin and when I want to look up a function under the cursor in the online api docs, I type '\da'
Here's the vimscipt code for the keymapping:
nnoremap <buffer> <LocalLeader>dda :silent call <SID>OpenURL('http://api.drush.ws/api/function/')<CR><C-L>
When the command is run, it writes the standard output from the shell into the current vim buffer, so the phrase:
"Created new window in existing browser session." will be written into the current buffer.
Also here's the openurl function:
function s:OpenURL(base)
let open = b:Drupal_info.OPEN_COMMAND
if open == ''
return
endif
let func = shellescape(expand('<cword>'))
if a:base == 'api.d.o'
if strlen(b:Drupal_info.CORE)
execute '!' . open . ' http://api.drupal.org/api/search/' .
\ b:Drupal_info.CORE . '/' . func
else
execute '!' . open . ' http://api.drupal.org/' . func
endif
else
execute '!' . open . ' ' . a:base . func
endif
endfun
How do I fix this/redirect stdout?
(I'm using ubuntu/gnome.)
Thanks!
I do not see anything that will put command output into the current buffer. But if you don’t want to observe command output at all, you can do one of two things:
Put silent in front of each ! (note: you must have the space after silent) and add redraw! command just before endfunction.
Replace every execute '!'.<...> with call system(<...>) (in this case having newline in arguments is much likely to cause bugs).
How can I redirect or pipe the output of an ex command into my current buffer or a file?
For example, I want to read the contents of all the registers into the current buffer, which in ex mode is shown using :registers.
:redir >name_of_registers_file
:registers
:redir END
:r name_of_registers_file
:help redir
The last command is very useful, since there are lots of options for redirection: to variables, to registers, how to append, further cornucopia.
I still find it weird and annoying that it uses END that way, but since everything else that can follow redir has to start with a non-word-character, at least it's not ambiguous.
PS AFAIK (which is pretty far in this case) there's no way to read it directly into the buffer: you have to store it in a register or a variable first. Check the help for the various options of how to do that.
PPS If you do want to do this using a variable —maybe to encapsulate it in a function and avoid clobbering registers or global variables— you'll have to convert the multiline string that gets written to the variable into a list. EG
:call append( '.', split(variable_you_redirected_to, "\n") )
Otherwise (if you just do append('.',var)) you end up with ^#'s (nulls) instead of newlines, since that's what vimscript uses to represent newlines in String variables.
edit: as #Bill Odom mentions, using :put =variable_you_redirected_to is a lot easier than the complicated append() expression. Thanks, Bill!
PPPS
I've written a snippet to make this stuff more convenient. It declares a function Redir(command, target) and a command R.
The command parses the last series of non-space characters as a redirection target and passes that to the function, which does the boilerplate to redirect the command output to the redirection target.
The command is everything after R and before the last space.
EG
" Store the vim buffer list in buffer_list.txt
:R ls >buffer_list.txt
" Store error messages emitted by a function being debugged
" in the 'unnamed register'
:R call FunctionBeingDebugged() #">
There are a few limitations with this: for example you won't be able to write to a filename that contains a space. The upside to this is that you don't have to quote your command. I've got it posted on gist.github.com, and I'll try to keep it updated if I end up improving it. Or you can fork it yourself</noeuphemism>!
Anyway the snippet is available here. It can be dropped into a .vimrc file or into a file in ~/.vim/plugins.
#intuited is right; the redir command is what you want. A one-liner like this will insert the output of :registers into the current buffer:
redir => m | silent registers | redir END | put=m
That's not something you'll want to type very often, however, and it's not exactly amenable to a key map. I found myself doing this fairly often, so I wrote a function and a handful of commands to make it easier. As a bonus, I can now send command output to a new window or new tab as easily as inserting it into the current buffer. Here's the code (with a few command examples at the very end):
" redir_messages.vim
"
" Inspired by the TabMessage function/command combo found
" at <http://www.jukie.net/~bart/conf/vimrc>.
"
function! RedirMessages(msgcmd, destcmd)
"
" Captures the output generated by executing a:msgcmd, then places this
" output in the current buffer.
"
" If the a:destcmd parameter is not empty, a:destcmd is executed
" before the output is put into the buffer. This can be used to open a
" new window, new tab, etc., before :put'ing the output into the
" destination buffer.
"
" Examples:
"
" " Insert the output of :registers into the current buffer.
" call RedirMessages('registers', '')
"
" " Output :registers into the buffer of a new window.
" call RedirMessages('registers', 'new')
"
" " Output :registers into a new vertically-split window.
" call RedirMessages('registers', 'vnew')
"
" " Output :registers to a new tab.
" call RedirMessages('registers', 'tabnew')
"
" Commands for common cases are defined immediately after the
" function; see below.
"
" Redirect messages to a variable.
"
redir => message
" Execute the specified Ex command, capturing any messages
" that it generates into the message variable.
"
silent execute a:msgcmd
" Turn off redirection.
"
redir END
" If a destination-generating command was specified, execute it to
" open the destination. (This is usually something like :tabnew or
" :new, but can be any Ex command.)
"
" If no command is provided, output will be placed in the current
" buffer.
"
if strlen(a:destcmd) " destcmd is not an empty string
silent execute a:destcmd
endif
" Place the messages in the destination buffer.
"
silent put=message
endfunction
" Create commands to make RedirMessages() easier to use interactively.
" Here are some examples of their use:
"
" :BufMessage registers
" :WinMessage ls
" :TabMessage echo "Key mappings for Control+A:" | map <C-A>
"
command! -nargs=+ -complete=command BufMessage call RedirMessages(<q-args>, '' )
command! -nargs=+ -complete=command WinMessage call RedirMessages(<q-args>, 'new' )
command! -nargs=+ -complete=command TabMessage call RedirMessages(<q-args>, 'tabnew' )
" end redir_messages.vim
:redir #a
:registers
:redir END
"ap
:redir #a redirects all messages from here on to a register named a. You follow this with your command whose output you want to capture (:registers in your case). :redir END ends the redirection. "ap means, "a uses the register named a and p puts the contents of the selected register into the current buffer.
See Capture ex command output at Vim Tips Wiki for more information :-)
In addition, :h :redir:
...To get the output of one command the |execute()| function can be used.
e.g.
put = execute('scriptnames')
put = execute('filter /vimfiles/ scriptnames')
It is not necessary to use a temporary variable as long as you can save the current buffer and are ok with appending the messages to the end of the current file.
From the Vim documentation:
:redi[r] >> {file} Redirect messages to file {file}. Append if {file}
already exists. {not in Vi}
http://vimdoc.sourceforge.net/htmldoc/various.html#:redir
So, to append the messages from :registers to the bottom of the current file, do this:
:write | redir >> % | silent registers | redir END | edit
:write the file so that any changes won't be lost
Begin redirecting output to %, the name of the current file.
Silently run the :registers command.
END redirecting to the file.
:edit the file to see the new changes.
You can also forcefully truncate the current file and replace it with the output messages:
:redir! > % | silent registers | redir END | edit!
But that is probably not what you want to do.
Unfortunately I have no rep, so I cannot add this as a comment to 'Francis Niu'.
The execute() function looks like the easiest way to accomplish this, and it was added in vim 8 .
Listed in the new/extended features on vim's github. version8.txt