c4ctrl/c4ctrl.vim

312 lines
9.8 KiB
VimL
Raw Normal View History

" This Vim plugin makes some functionality of the c4ctrl utility available
" from within Vim.
2017-03-27 16:24:28 +02:00
"
2017-04-11 18:56:25 +02:00
" Last Change: 2017 Apr 11
2017-03-27 16:24:28 +02:00
" Maintainer: Shy
" License: This file is placed in the public domain.
"
2017-04-06 18:45:51 +02:00
" Usage: C4ctrl [get | open PRESET | set [w] [p] [f] [-magic] | text | write]
2017-03-27 16:24:28 +02:00
if exists("g:loaded_c4ctrl")
finish
endif
let g:loaded_c4ctrl = 1
function s:FindConfigDir()
" ************************************************ "
" Returns the path of the configuration directory, "
" eg. '/home/somepony/.config/c4ctrl/' "
" ************************************************ "
2017-03-27 16:24:28 +02:00
" Run only once
2017-04-11 18:56:25 +02:00
if exists("s:config_dir")
return s:config_dir
2017-03-27 16:24:28 +02:00
endif
if expand("$XDG_CONFIG_DIR") != "$XDG_CONFIG_DIR"
2017-04-11 18:56:25 +02:00
let s:config_dir = expand("$XDG_CONFIG_DIR/c4ctrl/")
2017-03-27 16:24:28 +02:00
else
2017-04-11 18:56:25 +02:00
let s:config_dir = expand("$HOME/.config/c4ctrl/")
2017-03-27 16:24:28 +02:00
endif
2017-04-11 18:56:25 +02:00
if !isdirectory(s:config_dir)
echo "Could not access config dir:" s:config_dir
2017-03-27 16:24:28 +02:00
return ""
endif
2017-04-11 18:56:25 +02:00
return s:config_dir
2017-03-27 16:24:28 +02:00
endfunction
2017-04-11 18:56:25 +02:00
function C4ctrl(prev_cursor_pos, mods, first_line, last_line, command, ...) range
" *********************************************************************** "
" Make some functionality of the 'c4ctrl' command line utility available "
" from within Vim. "
" Available commands are 'get', 'open', 'set', 'text' and 'write'. "
" Arguments: "
" prev_cursor_pos -- cursor position as returned by getcurpos() "
" mods -- modifiers (:command variable <f-mods>) "
" first_line -- first line of range (:command <line1> "
" last_line -- last line of range (:command <line2> "
" command -- user command ('get', 'set' etc.) "
" [command options] -- optional command options "
" *********************************************************************** "
2017-04-03 18:03:45 +02:00
" Name of the executable.
2017-03-27 16:24:28 +02:00
let s:c4ctrl = "c4ctrl"
" This function will be called after a preset file has been loaded
2017-04-03 18:03:45 +02:00
" into the buffer.
2017-04-11 18:56:25 +02:00
function! s:SynHighlight()
" Match topics
syn match Identifier "\c^\s*[0-9a-z/]*\ze\s*="
" Match color values with 3 digits
syn match Number "\c=\s*\zs\(\s*[0-9a-f]\)\{3}"
" Match color values with 6 digits
syn match Number "\c=\s*\zs\(\s*[0-9a-f]\)\{6}"
" Match comments
syn match Comment "^\s*[#!\"].*"
" Match error: too few digits
syn match Error "\c=\s*\zs[0-9a-f]\{1,2}$"
" Match error: invalid chars as digit
syn match Error "\c=\s*\zs.*[^ \t0-9a-f]\+.*"
endfunction
" Check if we can excute c4ctrl or c4ctrl.py and modify the variable
" s:c4ctrl accordingly
2017-03-27 16:24:28 +02:00
if !executable(s:c4ctrl)
2017-04-03 18:03:45 +02:00
" Maybe we just need to add .py to the command?
2017-03-27 16:24:28 +02:00
if executable(s:c4ctrl.".py")
2017-04-03 18:03:45 +02:00
let s:c4ctrl .= ".py"
2017-03-27 16:24:28 +02:00
else
echoerr "Executable not found! Please put \"".s:c4ctrl."\" into your $PATH."
2017-04-03 18:03:45 +02:00
unlet s:c4ctrl
return
2017-03-27 16:24:28 +02:00
endif
endif
if stridx("get", a:command) == 0
" *********************************** "
" Read current status into new buffer "
" *********************************** "
2017-04-11 18:56:25 +02:00
execute a:mods "new"
silent execute "0 read !" s:c4ctrl "-o -"
2017-04-11 18:56:25 +02:00
normal 0gg
call s:SynHighlight()
elseif stridx("open", a:command) == 0
" ********************** "
" Edit an exiting preset "
" ********************** "
2017-03-27 16:24:28 +02:00
if !exists("a:1")
echo "Missing filename!"
return
endif
2017-04-11 18:56:25 +02:00
let s:config_dir = s:FindConfigDir()
if s:config_dir == ""
2017-03-27 16:24:28 +02:00
return
endif
2017-04-11 18:56:25 +02:00
let filename = s:config_dir . a:1
if !filereadable(filename)
echoerr "Error: could not open file" filename
2017-03-27 16:24:28 +02:00
return
endif
2017-03-28 17:50:56 +02:00
2017-04-11 18:56:25 +02:00
execute a:mods "new"
execute "edit" fnameescape(filename)
call s:SynHighlight()
elseif stridx("set", a:command) == 0
" ****************************** "
" Set preset from current buffer "
" ****************************** "
2017-03-27 16:24:28 +02:00
" Let's start by building a command line
2017-04-11 18:56:25 +02:00
let command_line = s:c4ctrl
2017-03-27 16:24:28 +02:00
if a:0 == 0
" If no room is given, set colors for all rooms
2017-04-11 18:56:25 +02:00
let command_line .= " -w - -p - -f -"
2017-03-27 16:24:28 +02:00
endif
2017-04-11 18:56:25 +02:00
for i in range(a:0)
let arg = a:000[i]
if strchars(arg) == 1
if stridx("wpf", arg) != -1
let command_line = printf("%s -%s -", command_line, arg)
2017-03-29 20:31:12 +02:00
endif
2017-04-11 18:56:25 +02:00
elseif stridx("-magic", arg) == 0
let command_line = printf("%s --magic", command_line)
2017-03-27 16:24:28 +02:00
endif
endfor
2017-04-11 18:56:25 +02:00
silent let ret = system(command_line, getline(a:first_line, a:last_line))
2017-03-27 16:24:28 +02:00
2017-04-11 18:56:25 +02:00
" Restore cursor position
call setpos('.', a:prev_cursor_pos)
elseif stridx("text", a:command) == 0
" ********************************************** "
" Send line under the cursor to the Kitchenlight "
" ********************************************** "
2017-03-27 16:24:28 +02:00
" Strip any ','
2017-04-11 18:56:25 +02:00
let txt = substitute(getline("."), ",", "", "g")
let ret = system(printf("%s -k text,%s", s:c4ctrl, shellescape(txt)))
elseif stridx("write", substitute(a:command, "!$", "", "")) == 0
" ********************************* "
" Save preset into config directory "
" ********************************* "
if !exists("a:1")
echo "Missing filename!"
return
endif
2017-04-11 18:56:25 +02:00
let s:config_dir = s:FindConfigDir()
if s:config_dir == ""
return
endif
2017-04-11 18:56:25 +02:00
let filename = s:config_dir . a:1
if strridx(a:command, "!") + 1 == len(a:command)
2017-03-29 20:31:12 +02:00
" Force if a '!' was appended to the command
2017-04-11 18:56:25 +02:00
execute "saveas!" fnameescape(filename)
else
2017-04-11 18:56:25 +02:00
execute "saveas" fnameescape(filename)
endif
else
" ****************** "
" Unknown command oO "
" ****************** "
echo "Unknown command:" a:command
echo "Valid commands are get, open, set, text and write"
2017-03-27 16:24:28 +02:00
endif
" Echo return if shell exited with an error
if v:shell_error
2017-04-11 18:56:25 +02:00
if exists("ret")
echoerr ret
endif
2017-03-27 16:24:28 +02:00
endif
2017-04-11 18:56:25 +02:00
unlet! s:c4ctrl s:config_dir
delfunction s:SynHighlight
2017-03-27 16:24:28 +02:00
endfunction
2017-03-27 16:24:28 +02:00
function s:C4ctrlCompletion(ArgLead, CmdLine, CursorPos)
" ****************************** "
" Custom command line completion "
" ****************************** "
" The name of the command we are adding to Vim
2017-04-11 18:56:25 +02:00
let command_name = "C4ctrl"
2017-04-11 20:07:10 +02:00
" A list of current cmd line arguments
let command_line = split(a:CmdLine)
" Check out if our name was abbreviated and modify accordingly
while index(command_line, command_name) == -1
let command_name = strpart(command_name, 0, len(command_name) - 1)
2017-04-11 18:56:25 +02:00
if len(command_name) == 0
" This should never happen, but let's not risk an infinite loop anyway
return ""
endif
endwhile
2017-04-11 20:07:10 +02:00
" Position of our command in the command line
let command_index = index(command_line, command_name)
2017-03-29 20:31:12 +02:00
try " We use the matching finally for cleaning up
2017-04-11 20:07:10 +02:00
if stridx("open", get(command_line, command_index + 1)) == 0 || (len(command_line) == command_index + 1 && a:ArgLead == command_name)
" *************************** "
" Complete the 'open' command "
" *************************** "
2017-04-11 20:07:10 +02:00
" ^ Note: the seconds part of the if rule (the part after '||') will
" eval to true if a filename matches our command name better than the
" actually given command name (eg. ':C4 open C4c')
2017-03-29 20:47:08 +02:00
if a:ArgLead != ""
2017-04-11 20:07:10 +02:00
if len(command_line) == command_index + 2
2017-03-31 17:31:54 +02:00
return "open"
endif
2017-04-11 20:07:10 +02:00
elseif len(command_line) > command_index + 2
2017-03-31 17:31:54 +02:00
" Do not return more than one file name
2017-03-29 20:47:08 +02:00
return ""
endif
2017-04-11 18:56:25 +02:00
let s:config_dir = s:FindConfigDir()
if s:config_dir == ""
2017-03-29 20:47:08 +02:00
return ""
endif
2017-04-11 18:56:25 +02:00
return join(map(glob(s:config_dir."*", 0, 1), "fnamemodify(v:val, ':t')"), "\n")
2017-03-29 20:47:08 +02:00
2017-04-11 20:07:10 +02:00
elseif stridx("get", get(command_line, command_index + 1)) == 0
" ************************** "
" Complete the 'get' command "
" ************************** "
2017-03-29 20:47:08 +02:00
if a:ArgLead != ""
return "get"
endif
2017-03-27 16:24:28 +02:00
return ""
2017-03-29 20:31:12 +02:00
2017-04-11 20:07:10 +02:00
elseif stridx("set", get(command_line, command_index + 1)) == 0
" ************************** "
" Complete the 'set' command "
" ************************** "
2017-03-29 20:47:08 +02:00
if a:ArgLead != ""
2017-04-06 18:45:51 +02:00
return "set\n-magic"
2017-03-29 20:47:08 +02:00
endif
2017-04-06 18:45:51 +02:00
return "w\np\nf\n-magic"
2017-03-29 20:31:12 +02:00
2017-04-11 20:07:10 +02:00
elseif stridx("text", get(command_line, command_index + 1)) == 0
" *************************** "
" Complete the 'text' command "
" *************************** "
2017-03-29 20:47:08 +02:00
if a:ArgLead != ""
return "text"
endif
return ""
2017-03-29 20:31:12 +02:00
2017-04-11 20:07:10 +02:00
elseif stridx("write", get(command_line, command_index + 1)) == 0 || (len(command_line) == command_index + 1 && a:ArgLead == command_name)
" **************************** "
" Complete the 'write' command "
" **************************** "
2017-04-11 20:07:10 +02:00
" ^ Note: the seconds part of the if rule (the part after '||') will
" eval to true if a filename matches our command name better than the
" actually given command name (eg. ':C4 open C4c')
2017-03-29 20:47:08 +02:00
if a:ArgLead != ""
2017-04-11 20:07:10 +02:00
if len(command_line) == command_index + 2
2017-03-31 17:31:54 +02:00
return "write"
endif
2017-04-11 20:07:10 +02:00
elseif len(command_line) > command_index + 2
2017-03-31 17:31:54 +02:00
" Do not return more than one file name
2017-03-29 20:47:08 +02:00
return ""
endif
2017-04-11 18:56:25 +02:00
let s:config_dir = s:FindConfigDir()
if s:config_dir == ""
2017-03-29 20:47:08 +02:00
return ""
endif
2017-04-11 18:56:25 +02:00
return join(map(glob(s:config_dir."*", 0, 1), "fnamemodify(v:val, ':t')"), "\n")
2017-03-29 20:31:12 +02:00
2017-04-11 20:07:10 +02:00
elseif len(command_line) == command_index + 1
" ************************** "
" Complete the first command "
" ************************** "
2017-03-29 20:47:08 +02:00
return "get\nopen\nset\ntext\nwrite"
else
return ""
endif
2017-03-27 16:24:28 +02:00
2017-03-29 20:47:08 +02:00
finally
2017-04-11 18:56:25 +02:00
unlet! s:config_dir
2017-03-29 20:47:08 +02:00
endtry
2017-03-27 16:24:28 +02:00
endfunction
2017-03-29 20:47:08 +02:00
if !exists(":C4ctrl")
" ********************** "
" Add our command to Vim "
" ********************** "
2017-04-11 18:56:25 +02:00
command -nargs=+ -complete=custom,s:C4ctrlCompletion -range=% C4ctrl call C4ctrl(getcurpos(), <f-mods>, <line1>, <line2>, <f-args>)
2017-03-27 16:24:28 +02:00
endif