123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- "=============================================================================
- " File: plugin/ui-functions.vim {{{1
- " Author: Luc Hermitte <EMAIL:hermitte {at} free {dot} fr>
- " <URL:http://code.google.com/p/lh-vim/>
- " License: GPLv3 with exceptions
- " <URL:http://code.google.com/p/lh-vim/wiki/License>
- " Version: 3.0.0
- " Created: 18th nov 2002
- " Last Update: $Date: 2012-03-19 19:09:15 +0100 (Mon, 19 Mar 2012) $ (19th Mar 2012)
- "------------------------------------------------------------------------
- " Description: Functions for the interaction with a User Interface.
- " The UI can be graphical or textual.
- " At first, this was designed to ease the syntax of
- " mu-template's templates.
- "
- " Option: {{{2
- " {[bg]:ui_type}
- " = "g\%[ui]",
- " = "t\%[ext]" ; the call must not be |:silent|
- " = "f\%[te]"
- " }}}2
- "------------------------------------------------------------------------
- " Installation: Drop this into one of your {rtp}/plugin/ directories.
- " History: {{{2
- " v0.01 Initial Version
- " v0.02
- " (*) Code "factorisations"
- " (*) Help on <F1> enhanced.
- " (*) Small changes regarding the parameter accepted
- " (*) Function SWITCH
- " v0.03
- " (*) Small bug fix with INPUT()
- " v0.04
- " (*) New function: WHICH()
- " v0.05
- " (*) In vim7e, inputdialog() returns a trailing '\n'. INPUT() strips the
- " NL character.
- " v0.06
- " (*) :s/echoerr/throw/ => vim7 only
- " v2.2.0
- " (*) menu to switch the ui_type
- " v2.2.6
- " (*) CONFIRM() and WHICH() accept lists of {choices}
- " v3.0.0 GPLv3
- "
- " TODO: {{{2
- " (*) Save the hl-User1..9 before using them
- " (*) Possibility other than &statusline:
- " echohl User1 |echon "bla"|echohl User2|echon "bli"|echohl None
- " (*) Wraps too long choices-line (length > term-width)
- " (*) Add to the documentation: "don't use CTRL-C to abort !!"
- " (*) Look if I need to support 'wildmode'
- " (*) 3rd mode: return string for FTE
- " (*) 4th mode: interaction in a scratch buffer
- "
- " }}}1
- "=============================================================================
- " Avoid reinclusion {{{1
- "
- if exists("g:loaded_ui_functions") && !exists('g:force_reload_ui_functions')
- finish
- endif
- let g:loaded_ui_functions = 1
- let s:cpo_save=&cpo
- set cpo&vim
- " }}}1
- "------------------------------------------------------------------------
- " External functions {{{1
- " Function: IF(var, then, else) {{{2
- function! IF(var,then, else)
- let o = s:Opt_type() " {{{3
- if o =~ 'g\%[ui]\|t\%[ext]' " {{{4
- return a:var ? a:then : a:else
- elseif o =~ 'f\%[te]' " {{{4
- return s:if_fte(a:var, a:then, a:else)
- else " {{{4
- throw "UI-Fns::IF(): Unkonwn user-interface style (".o.")"
- endif
- " }}}3
- endfunction
-
- " Function: SWITCH(var, case, action [, case, action] [default_action]) {{{2
- function! SWITCH(var, ...)
- let o = s:Opt_type() " {{{3
- if o =~ 'g\%[ui]\|t\%[ext]' " {{{4
- let explicit_def = ((a:0 % 2) == 1)
- let default = explicit_def ? a:{a:0} : ''
- let i = a:0 - 1 - explicit_def
- while i > 0
- if a:var == a:{i}
- return a:{i+1}
- endif
- let i -= 2
- endwhile
- return default
- elseif o =~ 'f\%[te]' " {{{4
- return s:if_fte(a:var, a:then, a:else)
- else " {{{4
- throw "UI-Fns::SWITCH(): Unkonwn user-interface style (".o.")"
- endif
- " }}}3
- endfunction
-
- " Function: CONFIRM(text [, choices [, default [, type]]]) {{{2
- function! CONFIRM(text, ...)
- " 1- Check parameters {{{3
- if a:0 > 4 " {{{4
- throw "UI-Fns::CONFIRM(): too many parameters"
- return 0
- endif
- " build the parameters string {{{4
- let i = 1
- while i <= a:0
- if i == 1
- if type(a:1) == type([])
- let params = string(join(a:1, "\n"))
- else
- let params = 'a:{1}'
- endif
- else | let params .= ',a:{'.i.'}'
- endif
- let i += 1
- endwhile
- " 2- Choose the correct way to execute according to the option {{{3
- let o = s:Opt_type()
- if o =~ 'g\%[ui]' " {{{4
- exe 'return confirm(a:text,'.params.')'
- elseif o =~ 't\%[ext]' " {{{4
- if !has('gui_running') && has('dialog_con')
- exe 'return confirm(a:text,'.params.')'
- else
- exe 'return s:confirm_text("none", a:text,'.params.')'
- endif
- elseif o =~ 'f\%[te]' " {{{4
- exe 'return s:confirm_fte(a:text,'.params.')'
- else " {{{4
- throw "UI-Fns::CONFIRM(): Unkonwn user-interface style (".o.")"
- endif
- " }}}3
- endfunction
-
- " Function: INPUT(prompt [, default ]) {{{2
- function! INPUT(prompt, ...)
- " 1- Check parameters {{{3
- if a:0 > 4 " {{{4
- throw "UI-Fns::INPUT(): too many parameters"
- return 0
- endif
- " build the parameters string {{{4
- let i = 1 | let params = ''
- while i <= a:0
- if i == 1 | let params = 'a:{1}'
- else | let params .= ',a:{'.i.'}'
- endif
- let i += 1
- endwhile
- " 2- Choose the correct way to execute according to the option {{{3
- let o = s:Opt_type()
- if o =~ 'g\%[ui]' " {{{4
- exe 'return matchstr(inputdialog(a:prompt,'.params.'), ".\\{-}\\ze\\n\\=$")'
- elseif o =~ 't\%[ext]' " {{{4
- exe 'return input(a:prompt,'.params.')'
- elseif o =~ 'f\%[te]' " {{{4
- exe 'return s:input_fte(a:prompt,'.params.')'
- else " {{{4
- throw "UI-Fns::INPUT(): Unkonwn user-interface style (".o.")"
- endif
- " }}}3
- endfunction
-
- " Function: COMBO(prompt, choice [, ... ]) {{{2
- function! COMBO(prompt, ...)
- " 1- Check parameters {{{3
- if a:0 > 4 " {{{4
- throw "UI-Fns::COMBO(): too many parameters"
- return 0
- endif
- " build the parameters string {{{4
- let i = 1
- while i <= a:0
- if i == 1 | let params = 'a:{1}'
- else | let params .= ',a:{'.i.'}'
- endif
- let i += 1
- endwhile
- " 2- Choose the correct way to execute according to the option {{{3
- let o = s:Opt_type()
- if o =~ 'g\%[ui]' " {{{4
- exe 'return confirm(a:prompt,'.params.')'
- elseif o =~ 't\%[ext]' " {{{4
- exe 'return s:confirm_text("combo", a:prompt,'.params.')'
- elseif o =~ 'f\%[te]' " {{{4
- exe 'return s:combo_fte(a:prompt,'.params.')'
- else " {{{4
- throw "UI-Fns::COMBO(): Unkonwn user-interface style (".o.")"
- endif
- " }}}3
- endfunction
-
- " Function: WHICH(function, prompt, choice [, ... ]) {{{2
- function! WHICH(fn, prompt, ...)
- " 1- Check parameters {{{3
- " build the parameters string {{{4
- let i = 1
- while i <= a:0
- if i == 1
- if type(a:1) == type([])
- let choices = a:1
- else
- let choices = split(a:1, "\n")
- endif
- let params = 'a:{1}'
- else | let params .= ',a:{'.i.'}'
- endif
- let i += 1
- endwhile
- " 2- Execute the function {{{3
- exe 'let which = '.a:fn.'(a:prompt,'.params.')'
- if 0 >= which | return ''
- else
- return substitute(choices[which-1], '&', '', '')
- endif
- " }}}3
- endfunction
-
- " Function: CHECK(prompt, choice [, ... ]) {{{2
- function! CHECK(prompt, ...)
- " 1- Check parameters {{{3
- if a:0 > 4 " {{{4
- throw "UI-Fns::CHECK(): too many parameters"
- return 0
- endif
- " build the parameters string {{{4
- let i = 1
- while i <= a:0
- if i == 1 | let params = 'a:{1}'
- else | let params .= ',a:{'.i.'}'
- endif
- let i += 1
- endwhile
- " 2- Choose the correct way to execute according to the option {{{3
- let o = s:Opt_type()
- if o =~ 'g\%[ui]' " {{{4
- exe 'return s:confirm_text("check", a:prompt,'.params.')'
- elseif o =~ 't\%[ext]' " {{{4
- exe 'return s:confirm_text("check", a:prompt,'.params.')'
- elseif o =~ 'f\%[te]' " {{{4
- exe 'return s:check_fte(a:prompt,'.params.')'
- else " {{{4
- throw "UI-Fns::CHECK(): Unkonwn user-interface style (".o.")"
- endif
- " }}}3
- endfunction
-
- " }}}1
- "------------------------------------------------------------------------
- " Options setting {{{1
- let s:OptionData = {
- \ "variable": "ui_type",
- \ "idx_crt_value": 1,
- \ "values": ['gui', 'text', 'fte'],
- \ "menu": { "priority": '500.2700', "name": '&Plugin.&LH.&UI type'}
- \}
-
- call lh#menu#def_toggle_item(s:OptionData)
-
- " }}}1
- "------------------------------------------------------------------------
- " Internal functions {{{1
- function! s:Option(name, default) " {{{2
- if exists('b:ui_'.a:name) | return b:ui_{a:name}
- elseif exists('g:ui_'.a:name) | return g:ui_{a:name}
- else | return a:default
- endif
- endfunction
-
-
- function! s:Opt_type() " {{{2
- return s:Option('type', 'gui')
- endfunction
-
- "
- " Function: s:status_line(current, hl [, choices] ) {{{2
- " a:current: current item
- " a:hl : Generic, Warning, Error
- function! s:status_line(current, hl, ...)
- " Highlightning {{{3
- if a:hl == "Generic" | let hl = '%1*'
- elseif a:hl == "Warning" | let hl = '%2*'
- elseif a:hl == "Error" | let hl = '%3*'
- elseif a:hl == "Info" | let hl = '%4*'
- elseif a:hl == "Question" | let hl = '%5*'
- else | let hl = '%1*'
- endif
-
- " Build the string {{{3
- let sl_choices = '' | let i = 1
- while i <= a:0
- if i == a:current
- let sl_choices .= ' '. hl .
- \ substitute(a:{i}, '&\(.\)', '%6*\1'.hl, '') . '%* '
- else
- let sl_choices .= ' ' .
- \ substitute(a:{i}, '&\(.\)', '%6*\1%*', '') . ' '
- endif
- let i += 1
- endwhile
- " }}}3
- return sl_choices
- endfunction
-
-
- " Function: s:confirm_text(box, text [, choices [, default [, type]]]) {{{2
- function! s:confirm_text(box, text, ...)
- let help = "/<esc>/<s-tab>/<tab>/<left>/<right>/<cr>/<F1>"
- " 1- Retrieve the parameters {{{3
- let choices = ((a:0>=1) ? a:1 : '&Ok')
- let default = ((a:0>=2) ? a:2 : (('check' == a:box) ? 0 : 1))
- let type = ((a:0>=3) ? a:3 : 'Generic')
- if 'none' == a:box | let prefix = ''
- elseif 'combo' == a:box | let prefix = '( )_'
- elseif 'check' == a:box | let prefix = '[ ]_'
- let help = '/ '.help
- else | let prefix = ''
- endif
-
-
- " 2- Retrieve the proposed choices {{{3
- " Prepare the hot keys
- let i = 0
- while i != 26
- let hotkey_{nr2char(i+65)} = 0
- let i += 1
- endwhile
- let hotkeys = '' | let help_k = '/'
- " Parse the choices
- let i = 0
- while choices != ""
- let i += 1
- let item = matchstr(choices, "^.\\{-}\\ze\\(\n\\|$\\)")
- let choices = matchstr(choices, "\n\\zs.*$")
- " exe 'anoremenu ]'.a:text.'.'.item.' :let s:choice ='.i.'<cr>'
- if ('check' == a:box) && (strlen(default)>=i) && (1 == default[i-1])
- " let choice_{i} = '[X]' . substitute(item, '&', '', '')
- let choice_{i} = '[X]_' . item
- else
- " let choice_{i} = prefix . substitute(item, '&', '', '')
- let choice_{i} = prefix . item
- endif
- if i == 1
- let list_choices = 'choice_{1}'
- else
- let list_choices .= ',choice_{'.i.'}'
- endif
- " Update the hotkey.
- let key = toupper(matchstr(choice_{i}, '&\zs.\ze'))
- let hotkey_{key} = i
- let hotkeys .= tolower(key) . toupper(key)
- let help_k .= tolower(key)
- endwhile
- let nb_choices = i
- if default > nb_choices | let default = nb_choices | endif
-
- " 3- Run an interactive text menu {{{3
- " Note: emenu can not be used through ":exe" {{{4
- " let wcm = &wcm
- " set wcm=<tab>
- " exe ':emenu ]'.a:text.'.'."<tab>"
- " let &wcm = wcm
- " 3.1- Preparations for the statusline {{{4
- " save the statusline
- let sl = &l:statusline
- " Color schemes for selected item {{{5
- :hi User1 term=inverse,bold cterm=inverse,bold ctermfg=Yellow
- \ guifg=Black guibg=Yellow
- :hi User2 term=inverse,bold cterm=inverse,bold ctermfg=LightRed
- \ guifg=Black guibg=LightRed
- :hi User3 term=inverse,bold cterm=inverse,bold ctermfg=Red
- \ guifg=Black guibg=Red
- :hi User4 term=inverse,bold cterm=inverse,bold ctermfg=Cyan
- \ guifg=Black guibg=Cyan
- :hi User5 term=inverse,bold cterm=inverse,bold ctermfg=LightYellow
- \ guifg=Black guibg=LightYellow
- :hi User6 term=inverse,bold cterm=inverse,bold ctermfg=LightGray
- \ guifg=DarkRed guibg=LightGray
- " }}}5
-
- " 3.2- Interactive loop {{{4
- let help = "\r-- Keys available (".help_k.help.")"
- " item selected at the start
- let i = ('check' != a:box) ? default : 1
- let direction = 0 | let toggle = 0
- while 1
- if 'combo' == a:box
- let choice_{i} = substitute(choice_{i}, '^( )', '(*)', '')
- endif
- " Colored statusline
- " Note: unfortunately the 'statusline' is a global option, {{{
- " not a local one. I the hope that may change, as it does not provokes any
- " error, I use '&l:statusline'. }}}
- exe 'let &l:statusline=s:status_line(i, type,'. list_choices .')'
- if has(':redrawstatus')
- redrawstatus!
- else
- redraw!
- endif
- " Echo the current selection
- echo "\r". a:text.' '.substitute(choice_{i}, '&', '', '')
- " Wait the user to hit a key
- let key=getchar()
- let complType=nr2char(key)
- " If the key hit matched awaited keys ...
- if -1 != stridx(" \<tab>\<esc>\<enter>".hotkeys,complType) ||
- \ (key =~ "\<F1>\\|\<right>\\|\<left>\\|\<s-tab>")
- if key == "\<F1>" " Help {{{5
- redraw!
- echohl StatusLineNC
- echo help
- echohl None
- let key=getchar()
- let complType=nr2char(key)
- endif
- " TODO: support CTRL-D
- if complType == "\<enter>" " Validate {{{5
- break
- elseif complType == " " " check box {{{5
- let toggle = 1
- elseif complType == "\<esc>" " Abort {{{5
- let i = -1 | break
- elseif complType == "\<tab>" || key == "\<right>" " Next {{{5
- let direction = 1
- elseif key =~ "\<left>\\|\<s-tab>" " Previous {{{5
- let direction = -1
- elseif -1 != stridx(hotkeys, complType ) " Hotkeys {{{5
- if '' == complType | continue | endif
- let direction = hotkey_{toupper(complType)} - i
- let toggle = 1
- " else
- endif
- " }}}5
- endif
- if direction != 0 " {{{5
- if 'combo' == a:box
- let choice_{i} = substitute(choice_{i}, '^(\*)', '( )', '')
- endif
- let i += direction
- if i > nb_choices | let i = 1
- elseif i == 0 | let i = nb_choices
- endif
- let direction = 0
- endif
- if toggle == 1 " {{{5
- if 'check' == a:box
- let choice_{i} = ((choice_{i}[1] == ' ')? '[X]' : '[ ]')
- \ . strpart(choice_{i}, 3)
- endif
- let toggle = 0
- endif
- endwhile " }}}4
- " 4- Terminate {{{3
- " Clear screen
- redraw!
-
- " Restore statusline
- let &l:statusline=sl
- " Return
- if (i == -1) || ('check' != a:box)
- return i
- else
- let r = '' | let i = 1
- while i <= nb_choices
- let r .= ((choice_{i}[1] == 'X') ? '1' : '0')
- let i += 1
- endwhile
- return r
- endif
- endfunction
- " }}}1
- "------------------------------------------------------------------------
- " Functions that insert fte statements {{{1
- " Function: s:if_fte(var, then, else) {{{2
- " Function: s:confirm_fte(text, [, choices [, default [, type]]]) {{{2
- " Function: s:input_fte(prompt [, default]) {{{2
- " Function: s:combo_fte(prompt, choice [, ...]) {{{2
- " Function: s:check_fte(prompt, choice [, ...]) {{{2
- " }}}1
- "------------------------------------------------------------------------
- let &cpo=s:cpo_save
- "=============================================================================
- " vim600: set fdm=marker:
|