This commit is contained in:
anon 2024-04-28 21:25:23 +02:00
commit a3b9ba5d92
49 changed files with 11472 additions and 314 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ vim/.vim/.netrwhist
cache.db
.cache/*
tags.vim
sigs.vim

View File

@ -48,7 +48,7 @@ export VISUAL="vim"
export BROWSER="librewolf"
export PAGER="less"
export IMAGEVIEWER="nomacs"
export MANPAGER='recursivelyExpandedAlias less'
export MANPAGER='less --mouse'
#pragma endregion
### Quick Access ###
#pragma region
@ -252,16 +252,6 @@ alias bat='bat --italic-text always'
alias hexedit='hexedit --color'
alias less='less --use-color'
export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
if [ -x /usr/bin/dircolors ]; then
[ -n "$LS_COLORS" ] || (test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)")
export LESS_TERMCAP_mb=$'\E[1;31m' # begin blink
export LESS_TERMCAP_md=$'\E[1;36m' # begin bold
export LESS_TERMCAP_me=$'\E[0m' # reset bold/blink
export LESS_TERMCAP_so=$'\E[01;33m' # begin reverse video
export LESS_TERMCAP_se=$'\E[0m' # reset reverse video
export LESS_TERMCAP_us=$'\E[1;32m' # begin underline
export LESS_TERMCAP_ue=$'\E[0m' # reset underline
fi
#pragma endregion
### Safety ###
#pragma region
@ -280,7 +270,7 @@ alias mkdir='mkdir -p'
alias lsblk='lsblk -o LABEL,NAME,SIZE,FSUSE%,RM,RO,TYPE,FSTYPE,MOUNTPOINTS'
alias hgrep='\history | grep'
alias history='history | tail -n 10'
alias clear="clear; env echo -e \"${FAVCOLESC}###\033[0m\"; dirs"
alias clear="\clear; env echo -e \"${FAVCOLESC}###\033[0m\"; dirs"
alias cal='cal --monday'
alias nmap='nmap --stats-every 5s'
#pragma endregion
@ -331,6 +321,7 @@ alias gpg='gpg -i --no-symkey-cache'
##### Lynx ####
export WWW_HOME="${HOME}/lynx_bookmarks.html"
##### locate ####
alias locate='locate --regexp'
alias locatei='locate -i'
##### figlet ####
alias figlet="figlet -w 120 -d ${MM}/Fonts/figlet-fonts/"
@ -338,6 +329,14 @@ alias figlet="figlet -w 120 -d ${MM}/Fonts/figlet-fonts/"
export FZF_DEFAULT_OPTS='--multi --no-mouse --height=10 --layout=reverse'
##### tmux ####
alias tmux='tmux new-session -t '0' || tmux'
##### stat ####
function statAlias() {
\stat $@ | perl -pe 's/(.*?): (.*)/\033[33;1m$1:\033[0m $2/'
du -h -s "$1"
}
alias stat="statAlias"
##### tgpt ####
alias tgpt="\tmux resize-window -x 80; tgpt -m"
#pragma endregion
#pragma endregion
@ -353,7 +352,8 @@ export PERL5LIB="$PERL5LIB:."
#pragma endregion
### Python ###
#pragma region
alias ipython="ipython -i ${MM}/Python/Pythonrc/init.py"
export PYTHONSTARTUP="${HOME}/.pythonrc"
alias ipython="ipython -i '${PYTHONSTARTUP}'"
alias vsource='source ./venv/bin/activate'
#pragma endregion
### Java ###
@ -374,13 +374,23 @@ export PATH="${PATH}:${HOME}/.cargo/bin/"
# Custom Additions
#pragma region
function ffgrep() {
fgrep "$1" ./**/* 2> /dev/null
WHERE='.'
[ "$2" != "" ] && WHERE="$2"
[ -d "$WHERE" ] && WHERE="${WHERE}/**/*"
fgrep "$1" ${WHERE} 2> /dev/null
}
function signin(){
\sudo -u $1 bash
}
function testscript() {
[ -n "$1" ] && SUFFIX=".$1"
I=$(mktemp --tmpdir=$(realpath ~/Swap/tests/) --suffix="${SUFFIX}" XXXX)
echo "\033[31;1m${I}\033[0m"
$EDITOR $I
}
alias cbash='bash --norc --noprofile --init-file <(echo "unset HISTFILE")'
alias resource='source ~/.bashrc'
alias dmake='make --debug --trace --warn-undefined-variables'
alias resource='unalias -a; source ~/.bashrc'
alias xclip='xclip -selection clipboard'
alias tt='tt_with_high_score.sh'
#pragma endregion
@ -392,7 +402,8 @@ source ${SRCF}/w.rc # watch (clock)
source ${SRCF}/cd.rc
source ${SRCF}/sudo.rc
source ${SRCF}/fzfind.rc
source ${SRCF}/ls_colors.rc
[[ -f /usr/share/bash-completion/bash_completion ]] && \
. /usr/share/bash-completion/bash_completion
if [ "$USER" == "root" ]; then

View File

@ -1,87 +0,0 @@
#!/bin/bash
[ -z "$CTRLFMODE" ] && CTRLFMODE="path"
[ -z "$CTRLFMETHOD" ] && CTRLFMETHOD="find"
#CTRLCACHE="/home/anon/Desktop/"
function ctrl_f_mode(){
read -n 1 M
case $M in
p) CTRLFMODE="path";;
u) CTRLFMODE="user";;
o) CTRLFMODE="opt";;
c) CTRLFMODE="cmd" ;;
v) CTRLFMODE="var" ;;
*) CTRLFMODE="path";;
esac
env echo -e "\033[1mctrl-f mode: \"\033[0m${CTRLFMODE}\""
}
function echo_readline_line(){
PS1_CLEANED="${PS1//\\\[/}"
PS1_CLEANED="${PS1_CLEANED//\\\]/}"
env echo -e "${PS1_CLEANED}${1:0:${2}}\033[45m \033[0m${1:${2}}"
#env echo -e "${PS1}${1:0:${2}}\033[45m \033[0m${1:${2}}"
}
function ctrl_f(){
# Show command and substitution position
echo_readline_line "${READLINE_LINE}" "${READLINE_POINT}"
# Get narrowing substring
OPX=""
if [ "${READLINE_LINE:$(expr $READLINE_POINT - 1):1}" != " " ]; then
OPX=$(lastWord "${READLINE_LINE:0:${READLINE_POINT}}")
fi
#echo "'$PX'"
# Decide possible completions and use fzf for selection
case $CTRLFMODE in
"path")
if [ $CTRLFMETHOD == "find" ]; then
PX="$OPX"
STR=$(eval find ./"$PX/" 2> /dev/null | fzf --multi=1)
elif [ $CTRLFMETHOD == "locate" ]; then
PX="$(realpath $PWD/$OPX)"
STR=$(eval locate --existing --regex $PX/'.*' 2> /dev/null | fzf --multi=1)
else
echo -e "\033[31;1mNonsensical \033[34;1m\${CTRLFMETHOD} \033[31;1mvalue.\033[0m"
fi
;;
"opt")
#get command
#check catche
#parse
;;
"user")
if [ "$PX" != "" ]; then
STR="$(compgen -u ${PX} | fzf --multi=1)"
else
STR="$(compgen -u | fzf --multi=1)"
fi
;;
"cmd")
if [ "$PX" != "" ]; then
STR="$(compgen -c ${PX} | uniq | fzf --multi=1)"
else
STR="$(compgen -c | uniq | fzf --multi=1)"
fi
;;
"var")
if [ "$PX" != "" ]; then
STR="$(compgen -v ${PX} | fzf --multi=1)"
else
STR="$(compgen -v | fzf --multi=1)"
fi
;;
esac
# Remove ${PX}
STR="${STR/${PX}/}"
# Write $READLINE_LINE
[ -z "$STR" ] && return
if [ "$CTRLFMODE" == "path" ]; then # quote paths
READLINE_LINE="${READLINE_LINE:0:$(expr ${READLINE_POINT} - ${#OPX})}\"${OPX}${STR}\"${READLINE_LINE:${READLINE_POINT}}" # start_til_px + '"' + px + str '"' + rest
READLINE_POINT=$(expr ${READLINE_POINT} + ${#OPX} + ${#STR} + 2) # +2 for the '"'s
else
READLINE_LINE="${READLINE_LINE:0:$(expr ${READLINE_POINT} - ${#OPX})}${OPX}${STR}${READLINE_LINE:${READLINE_POINT}}" # start_til_px + px + str + rest
READLINE_POINT=$(expr ${READLINE_POINT} + ${#OPX} + ${#STR})
fi
}
bind -x '"\C-e": ctrl_f_mode'
bind -x '"\C-f": ctrl_f'

View File

@ -1 +0,0 @@
alias bc="bc -l"

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
export PERL5LIB="$PERL5LIB:."

648
bash/.dir_colors Normal file
View File

@ -0,0 +1,648 @@
*.7z 38;5;40
*.WARC 38;5;40
*.a 38;5;40
*.arj 38;5;40
*.br 38;5;40
*.bz2 38;5;40
*.cpio 38;5;40
*.gz 38;5;40
*.lrz 38;5;40
*.lz 38;5;40
*.lzma 38;5;40
*.lzo 38;5;40
*.rar 38;5;40
*.s7z 38;5;40
*.sz 38;5;40
*.tar 38;5;40
*.tbz 38;5;40
*.tgz 38;5;40
*.warc 38;5;40
*.xz 38;5;40
*.z 38;5;40
*.zip 38;5;40
*.zipx 38;5;40
*.zoo 38;5;40
*.zpaq 38;5;40
*.zst 38;5;40
*.zstd 38;5;40
*.zz 38;5;40
*@.service 38;5;45
*AUTHORS 38;5;220;1
*CHANGELOG 38;5;220;1
*CHANGELOG.md 38;5;220;1
*CHANGES 38;5;220;1
*CODEOWNERS 38;5;220;1
*CONTRIBUTING 38;5;220;1
*CONTRIBUTING.md 38;5;220;1
*CONTRIBUTORS 38;5;220;1
*COPYING 38;5;220;1
*COPYRIGHT 38;5;220;1
*CodeResources 38;5;239
*Containerfile 38;5;155
*Dockerfile 38;5;155
*HISTORY 38;5;220;1
*INSTALL 38;5;220;1
*LICENSE 38;5;220;1
*LICENSE.md 38;5;220;1
*LS_COLORS 48;5;89;38;5;197;1;3;4;7
*MANIFEST 38;5;243
*Makefile 38;5;155
*NOTICE 38;5;220;1
*PATENTS 38;5;220;1
*PkgInfo 38;5;239
*README 38;5;220;1
*README.md 38;5;220;1
*README.rst 38;5;220;1
*VERSION 38;5;220;1
*authorized_keys 1
*cfg 1
*conf 1
*config 1
*core 38;5;241
*id_dsa 38;5;192;3
*id_ecdsa 38;5;192;3
*id_ed25519 38;5;192;3
*id_rsa 38;5;192;3
*known_hosts 1
*lock 38;5;248
*lockfile 38;5;248
*pm_to_blib 38;5;240
*rc 1
*.1p 38;5;7
*.32x 38;5;213
*.3g2 38;5;115
*.3ga 38;5;137;1
*.3gp 38;5;115
*.3p 38;5;7
*.82p 38;5;121
*.83p 38;5;121
*.8eu 38;5;121
*.8xe 38;5;121
*.8xp 38;5;121
*.A64 38;5;213
*.BAT 38;5;172
*.BUP 38;5;241
*.C 38;5;81
*.CFUserTextEncoding 38;5;239
*.DS_Store 38;5;239
*.F 38;5;81
*.F03 38;5;81
*.F08 38;5;81
*.F90 38;5;81
*.F95 38;5;81
*.H 38;5;110
*.IFO 38;5;114
*.JPG 38;5;97
*.M 38;5;110
*.MOV 38;5;114
*.PDF 38;5;141
*.PFA 38;5;66
*.PL 38;5;160
*.R 38;5;49
*.RData 38;5;178
*.Rproj 38;5;11
*.S 38;5;110
*.S3M 38;5;137;1
*.SKIP 38;5;244
*.TIFF 38;5;97
*.VOB 38;5;115;1
*.a00 38;5;213
*.a52 38;5;213
*.a64 38;5;213
*.a78 38;5;213
*.aac 38;5;137;1
*.accdb 38;5;60
*.accde 38;5;60
*.accdr 38;5;60
*.accdt 38;5;60
*.adf 38;5;213
*.adoc 38;5;184
*.afm 38;5;66
*.agda 38;5;81
*.agdai 38;5;110
*.ahk 38;5;41
*.ai 38;5;99
*.aiff 38;5;136;1
*.alac 38;5;136;1
*.allow 38;5;112
*.am 38;5;242
*.amr 38;5;137;1
*.ape 38;5;136;1
*.apk 38;5;215
*.application 38;5;116
*.aria2 38;5;241
*.asc 38;5;192;3
*.asciidoc 38;5;184
*.asf 38;5;115
*.asm 38;5;81
*.ass 38;5;117
*.astro 38;5;135;1
*.atr 38;5;213
*.au 38;5;137;1
*.automount 38;5;45
*.avi 38;5;114
*.awk 38;5;172
*.bak 38;5;241
*.bash 38;5;172
*.bash_login 1
*.bash_logout 1
*.bash_profile 1
*.bat 38;5;172
*.bfe 38;5;192;3
*.bib 38;5;178
*.bin 38;5;124
*.bmp 38;5;97
*.bsp 38;5;215
*.c 38;5;81
*.c++ 38;5;81
*.cab 38;5;215
*.caf 38;5;137;1
*.cap 38;5;29
*.car 38;5;57
*.cbr 38;5;141
*.cbz 38;5;141
*.cc 38;5;81
*.cda 38;5;136;1
*.cdi 38;5;213
*.cdr 38;5;97
*.chm 38;5;141
*.cjs 38;5;074;1
*.cl 38;5;81
*.clj 38;5;41
*.cljc 38;5;41
*.cljs 38;5;41
*.cljw 38;5;41
*.cnc 38;5;7
*.coffee 38;5;079;1
*.comp 38;5;136
*.containerignore 38;5;240
*.cp 38;5;81
*.cpp 38;5;81
*.cr 38;5;81
*.crx 38;5;215
*.cs 38;5;81
*.css 38;5;105;1
*.csv 38;5;78
*.ctp 38;5;81
*.cue 38;5;116
*.cxx 38;5;81
*.dart 38;5;51
*.dat 38;5;137;1
*.db 38;5;60
*.deb 38;5;215
*.def 38;5;7
*.deny 38;5;196
*.description 38;5;116
*.device 38;5;45
*.dhall 38;5;178
*.dicom 38;5;97
*.diff 48;5;197;38;5;232
*.directory 38;5;116
*.divx 38;5;114
*.djvu 38;5;141
*.dll 38;5;241
*.dmg 38;5;215
*.dmp 38;5;29
*.doc 38;5;111
*.dockerignore 38;5;240
*.docm 38;5;111;4
*.docx 38;5;111
*.drw 38;5;99
*.dtd 38;5;178
*.dts 38;5;137;1
*.dump 38;5;241
*.dwg 38;5;216
*.dylib 38;5;241
*.ear 38;5;215
*.ejs 38;5;135;1
*.el 38;5;81
*.elc 38;5;241
*.eln 38;5;241
*.eml 38;5;90;1
*.enc 38;5;192;3
*.entitlements 1
*.epf 1
*.eps 38;5;99
*.epsf 38;5;99
*.epub 38;5;141
*.err 38;5;160;1
*.error 38;5;160;1
*.etx 38;5;184
*.ex 38;5;7
*.example 38;5;7
*.f 38;5;81
*.f03 38;5;81
*.f08 38;5;81
*.f4v 38;5;115
*.f90 38;5;81
*.f95 38;5;81
*.fcm 38;5;137;1
*.feature 38;5;7
*.fish 38;5;172
*.flac 38;5;136;1
*.flif 38;5;97
*.flv 38;5;115
*.fm2 38;5;213
*.fmp12 38;5;60
*.fnt 38;5;66
*.fon 38;5;66
*.for 38;5;81
*.fp7 38;5;60
*.frag 38;5;136
*.ftn 38;5;81
*.fvd 38;5;124
*.fxml 38;5;178
*.gb 38;5;213
*.gba 38;5;213
*.gbc 38;5;213
*.gbr 38;5;7
*.gel 38;5;213
*.gemspec 38;5;41
*.ger 38;5;7
*.gg 38;5;213
*.ggl 38;5;213
*.gif 38;5;97
*.git 38;5;197
*.gitattributes 38;5;240
*.github 38;5;197
*.gitignore 38;5;240
*.gitmodules 38;5;240
*.go 38;5;81
*.gp3 38;5;115
*.gp4 38;5;115
*.gpg 38;5;192;3
*.gs 38;5;81
*.h 38;5;110
*.h++ 38;5;110
*.hi 38;5;110
*.hidden-color-scheme 1
*.hidden-tmTheme 1
*.hin 38;5;242
*.hjson 38;5;178
*.hpp 38;5;110
*.hs 38;5;81
*.htm 38;5;125;1
*.html 38;5;125;1
*.http 38;5;90;1
*.hxx 38;5;110
*.icns 38;5;97
*.ico 38;5;97
*.ics 38;5;7
*.ii 38;5;110
*.img 38;5;124
*.iml 38;5;166
*.in 38;5;242
*.info 38;5;184
*.ini 1
*.ipa 38;5;215
*.ipk 38;5;213
*.ipynb 38;5;41
*.iso 38;5;124
*.j64 38;5;213
*.jad 38;5;215
*.jar 38;5;215
*.java 38;5;079;1
*.jhtm 38;5;125;1
*.jpeg 38;5;97
*.jpg 38;5;97
*.js 38;5;074;1
*.jsm 38;5;079;1
*.json 38;5;178
*.json5 38;5;178
*.jsonc 38;5;178
*.jsonl 38;5;178
*.jsonnet 38;5;178
*.jsp 38;5;079;1
*.jsx 38;5;074;1
*.jxl 38;5;97
*.kak 38;5;172
*.key 38;5;166
*.lagda 38;5;81
*.lagda.md 38;5;81
*.lagda.rst 38;5;81
*.lagda.tex 38;5;81
*.last-run 1
*.less 38;5;105;1
*.lhs 38;5;81
*.libsonnet 38;5;142
*.lisp 38;5;81
*.lnk 38;5;39
*.localized 38;5;239
*.localstorage 38;5;60
*.log 38;5;190
*.lua 38;5;81
*.m 38;5;110
*.m2v 38;5;114
*.m3u 38;5;116
*.m3u8 38;5;116
*.m4 38;5;242
*.m4a 38;5;137;1
*.m4v 38;5;114
*.map 38;5;7
*.markdown 38;5;184
*.md 38;5;184
*.md5 38;5;116
*.mdb 38;5;60
*.mde 38;5;60
*.mdump 38;5;241
*.mdx 38;5;184
*.merged-ca-bundle 1
*.mf 38;5;7
*.mfasl 38;5;7
*.mht 38;5;125;1
*.mi 38;5;7
*.mid 38;5;136;1
*.midi 38;5;136;1
*.mjs 38;5;074;1
*.mkd 38;5;184
*.mkv 38;5;114
*.ml 38;5;81
*.mm 38;5;7
*.mobi 38;5;141
*.mod 38;5;137;1
*.moon 38;5;81
*.mount 38;5;45
*.mov 38;5;114
*.mp3 38;5;137;1
*.mp4 38;5;114
*.mp4a 38;5;137;1
*.mpeg 38;5;114
*.mpg 38;5;114
*.msg 38;5;178
*.msql 38;5;222
*.mtx 38;5;7
*.mustache 38;5;135;1
*.mysql 38;5;222
*.nc 38;5;60
*.ndjson 38;5;178
*.nds 38;5;213
*.nes 38;5;213
*.nfo 38;5;184
*.nib 38;5;57
*.nim 38;5;81
*.nimble 38;5;81
*.nix 38;5;155
*.norg 38;5;184
*.nrg 38;5;124
*.nth 38;5;97
*.numbers 38;5;112
*.o 38;5;241
*.odb 38;5;111
*.odp 38;5;166
*.ods 38;5;112
*.odt 38;5;111
*.oga 38;5;137;1
*.ogg 38;5;137;1
*.ogm 38;5;114
*.ogv 38;5;115
*.old 38;5;242
*.opus 38;5;137;1
*.org 38;5;184
*.orig 38;5;241
*.otf 38;5;66
*.out 38;5;242
*.p12 38;5;192;3
*.p7s 38;5;192;3
*.pacnew 38;5;33
*.pages 38;5;111
*.pak 38;5;215
*.part 38;5;239
*.patch 48;5;197;38;5;232;1
*.path 38;5;45
*.pbxproj 1
*.pc 38;5;7
*.pcap 38;5;29
*.pcb 38;5;7
*.pcf 1
*.pcm 38;5;136;1
*.pdf 38;5;141
*.pem 38;5;192;3
*.pfa 38;5;66
*.pfb 38;5;66
*.pfm 38;5;66
*.pgn 38;5;178
*.pgp 38;5;192;3
*.pgsql 38;5;222
*.php 38;5;81
*.pi 38;5;7
*.pid 38;5;248
*.pk3 38;5;215
*.pl 38;5;208
*.plist 1
*.plt 38;5;7
*.ply 38;5;216
*.pm 38;5;203
*.png 38;5;97
*.pod 38;5;184
*.pot 38;5;7
*.pps 38;5;166
*.ppt 38;5;166
*.ppts 38;5;166
*.pptsm 38;5;166;4
*.pptx 38;5;166
*.pptxm 38;5;166;4
*.prisma 38;5;222
*.profile 1
*.properties 38;5;116
*.prql 38;5;222
*.ps 38;5;99
*.psd 38;5;97
*.psf 1
*.pug 38;5;135;1
*.pxd 38;5;97
*.pxm 38;5;97
*.py 38;5;41
*.pyc 38;5;240
*.qcow 38;5;124
*.r 38;5;49
*.r[0-9]{0,2} 38;5;239
*.rake 38;5;155
*.rb 38;5;41
*.rdata 38;5;178
*.rdf 38;5;7
*.rkt 38;5;81
*.rlib 38;5;241
*.rmvb 38;5;114
*.rnc 38;5;178
*.rng 38;5;178
*.rom 38;5;213
*.rpm 38;5;215
*.rs 38;5;81
*.rss 38;5;178
*.rst 38;5;184
*.rstheme 1
*.rtf 38;5;111
*.ru 38;5;7
*.s 38;5;110
*.s3m 38;5;137;1
*.sample 38;5;114
*.sass 38;5;105;1
*.sassc 38;5;244
*.sav 38;5;213
*.sc 38;5;41
*.scala 38;5;41
*.scan 38;5;242
*.sch 38;5;7
*.scm 38;5;7
*.scpt 38;5;219
*.scss 38;5;105;1
*.sed 38;5;172
*.service 38;5;45
*.sfv 38;5;116
*.sgml 38;5;178
*.sh 38;5;172
*.sid 38;5;137;1
*.sig 38;5;192;3
*.signature 38;5;192;3
*.sis 38;5;7
*.sms 38;5;213
*.snapshot 38;5;45
*.socket 38;5;45
*.sparseimage 38;5;124
*.spl 38;5;7
*.spv 38;5;217
*.sql 38;5;222
*.sqlite 38;5;60
*.srt 38;5;117
*.ssa 38;5;117
*.st 38;5;213
*.stackdump 38;5;241
*.state 38;5;248
*.stderr 38;5;160;1
*.stl 38;5;216
*.storyboard 38;5;196
*.strings 1
*.sty 38;5;7
*.sub 38;5;117
*.sublime-build 1
*.sublime-commands 1
*.sublime-keymap 1
*.sublime-project 1
*.sublime-settings 1
*.sublime-snippet 1
*.sublime-workspace 1
*.sug 38;5;7
*.sup 38;5;117
*.svelte 38;5;135;1
*.svg 38;5;99
*.swap 38;5;45
*.swift 38;5;219
*.swo 38;5;244
*.swp 38;5;244
*.sx 38;5;81
*.t 38;5;114
*.target 38;5;45
*.tcc 38;5;110
*.tcl 38;5;64;1
*.tdy 38;5;7
*.tex 38;5;184
*.textile 38;5;184
*.tf 38;5;168
*.tfm 38;5;7
*.tfnt 38;5;7
*.tfstate 38;5;168
*.tfvars 38;5;168
*.tg 38;5;7
*.theme 38;5;116
*.tif 38;5;97
*.tiff 38;5;97
*.timer 38;5;45
*.tmTheme 1
*.tmp 38;5;244
*.toast 38;5;124
*.toml 38;5;178
*.torrent 38;5;116
*.ts 38;5;074;1
*.tsv 38;5;78
*.tsx 38;5;074;1
*.ttf 38;5;66
*.twig 38;5;81
*.txt 38;5;253
*.typelib 38;5;60
*.un~ 38;5;241
*.urlview 38;5;116
*.user-ca-bundle 1
*.v 38;5;81
*.vala 38;5;81
*.vapi 38;5;81
*.vb 38;5;81
*.vba 38;5;81
*.vbs 38;5;81
*.vcard 38;5;7
*.vcd 38;5;124
*.vcf 38;5;7
*.vdf 38;5;215
*.vdi 38;5;124
*.vert 38;5;136
*.vfd 38;5;124
*.vhd 38;5;124
*.vhdx 38;5;124
*.vim 38;5;172
*.viminfo 1
*.vmdk 38;5;124
*.vob 38;5;115;1
*.vpk 38;5;215
*.vtt 38;5;117
*.vue 38;5;135;1
*.war 38;5;215
*.wav 38;5;136;1
*.webloc 38;5;116
*.webm 38;5;115
*.webp 38;5;97
*.wgsl 38;5;97
*.wma 38;5;137;1
*.wmv 38;5;114
*.woff 38;5;66
*.woff2 38;5;66
*.wrl 38;5;216
*.wv 38;5;136;1
*.wvc 38;5;136;1
*.xcconfig 1
*.xcf 38;5;7
*.xcsettings 1
*.xcuserstate 1
*.xcworkspacedata 1
*.xib 38;5;208
*.xla 38;5;76
*.xln 38;5;7
*.xls 38;5;112
*.xlsx 38;5;112
*.xlsxm 38;5;112;4
*.xltm 38;5;73;4
*.xltx 38;5;73
*.xml 38;5;178
*.xpi 38;5;215
*.xpm 38;5;97
*.xsd 38;5;178
*.xsh 38;5;41
*.yaml 38;5;178
*.yml 38;5;178
*.z[0-9]{0,2} 38;5;239
*.zcompdump 38;5;241
*.zig 38;5;81
*.zlogin 1
*.zlogout 1
*.zprofile 1
*.zsh 38;5;172
*.zshenv 1
*.zwc 38;5;241
*.zx[0-9]{0,2} 38;5;239
bd 38;5;68
ca 38;5;17
cd 38;5;113;1
di 38;5;30
do 38;5;127
ex 38;5;208;1
pi 38;5;126
fi 0
ln target
mh 38;5;222;1
no 0
or 48;5;196;38;5;232;1
ow 38;5;220;1
sg 48;5;3;38;5;0
su 38;5;220;1;3;100;1
so 38;5;197
st 38;5;86;48;5;234
tw 48;5;235;38;5;139;3

View File

@ -3,6 +3,7 @@
set echo-control-characters off
# Color suggestions apropriate for filetype (see $LS_COLORS)
set colored-stats on
set colored-completion-prefix on
# Briefly highlight matching parenthesies
set blink-matching-paren on
# Do not page completion suggestions
@ -18,3 +19,6 @@
set completion-ignore-case on
# '-' == '_'
set completion-map-case on
# Show results AND cycle results
"\e[Z":menu-complete
set show-all-if-ambiguous on

View File

@ -2,3 +2,6 @@
link-style=blue
active-link-style=yellow,bold
match-style=green
#info
\r select-reference-this-line

View File

@ -1,4 +0,0 @@
#!/bin/bash
xset r rate 180 40
setxkbmap -option caps:swapescape

View File

@ -1,14 +1,7 @@
import os
import atexit
import readline
from sys import *
from subprocess import *
from shlex import *
from numpy import *
from time import *
import re
histfile = os.path.join(os.environ['HOME'], "mm/Python/Pythonrc", '.python_history')
try:
readline.read_history_file(histfile)
except IOError:
print('I/O Error while reading history file "' + histfile + '"')
atexit.register(readline.write_history_file, histfile)
del os, histfile, readline

View File

@ -6,8 +6,8 @@ T: sudo rc-service tor restart
n: nnn
N: sudo rc-service NetworkManager restart
p: git push
4: ssh root@192.168.0.144
6: ssh 192.168.0.206
4: ssh root@${ROOK}
6: ssh ${BTS}
c: clifm
D: export DEBUG=1
b: newsboat

View File

@ -0,0 +1,211 @@
"======================================================================
"
" main.vim -
"
" Created by skywind on 2022/08/24
" Last Modified: 2022/08/24 20:24:47
"
"======================================================================
" vim: set ts=4 sw=4 tw=78 noet :
"----------------------------------------------------------------------
" extension map
"----------------------------------------------------------------------
let g:quickui = get(g:, 'quickui', {})
let s:quickui = {}
"----------------------------------------------------------------------
" internal
"----------------------------------------------------------------------
let s:private = {}
let s:private.quickui = {}
"----------------------------------------------------------------------
" initialize
"----------------------------------------------------------------------
function! s:init()
let quickui = {}
for key in keys(s:quickui)
let quickui[key] = s:quickui[key]
endfor
for key in keys(g:quickui)
let quickui[key] = g:quickui[key]
endfor
let names = keys(quickui)
call sort(names)
let s:private.quickui = quickui
let s:private.names = names
endfunc
"----------------------------------------------------------------------
" help
"----------------------------------------------------------------------
function! s:help(opts, argv)
endfunc
"----------------------------------------------------------------------
" list extension
"----------------------------------------------------------------------
function! s:list(opts, argv)
let rows = []
let highmap = {}
let index = 1
let rows += [['Extension', 'Help']]
let highmap['0,0'] = 'Title'
let highmap['0,1'] = 'Title'
for name in s:private.names
let help = get(s:private.quickui[name], 'help', '')
let rows += [[name, help]]
let highmap[index . ',0'] = 'Keyword'
let highmap[index . ',1'] = 'Statement'
let index += 1
endfor
call quickui#utils#print_table(rows, highmap)
endfunc
"----------------------------------------------------------------------
" main cmd
"----------------------------------------------------------------------
function! quickui#command#run(bang, cmdline) abort
let [cmdline, op1] = quickui#core#extract_opts(a:cmdline)
let cmdline = quickui#core#string_strip(cmdline)
let name = ''
if cmdline =~# '^\w\+'
let name = matchstr(cmdline, '^\w\+')
let cmdline = substitute(cmdline, '^\w\+\s*', '', '')
endif
let name = quickui#core#string_strip(name)
let [cmdline, op2] = quickui#core#extract_opts(cmdline)
let op2.cmdline = quickui#core#string_strip(cmdline)
let opts = deepcopy(op1)
for k in keys(op2)
let opts[k] = op2[k]
endfor
let argv = quickui#core#split_argv(cmdline)
call s:init()
if name == ''
if has_key(op1, 'h')
call s:help(opts, argv)
elseif has_key(op1, 'l')
call s:list(opts, argv)
endif
return 0
endif
if has_key(s:private.quickui, name) == 0
call quickui#utils#errmsg('invalid extension name: ' . name)
return -1
endif
let obj = s:private.quickui[name]
if has_key(obj, 'run') == 0
call quickui#utils#errmsg('not find "run" funcref in extension: ' . name)
return -2
endif
let hr = call(obj.run, [opts, argv])
return hr
endfunc
"----------------------------------------------------------------------
" command line completion
"----------------------------------------------------------------------
function! quickui#command#complete(ArgLead, CmdLine, CursorPos)
let candidate = []
call s:init()
if a:ArgLead =~ '^-'
let flags = ['-h', '-l']
for flag in flags
if stridx(flag, a:ArgLead) == 0
let candidate += [flag]
endif
endfor
return candidate
endif
for name in s:private.names
if stridx(name, a:ArgLead) == 0
let candidate += [name]
endif
endfor
return candidate
endfunc
"----------------------------------------------------------------------
" sub: main menu
"----------------------------------------------------------------------
function! s:sub_menu(opts, argv) abort
let argv = a:argv
if len(argv) == 0
call quickui#menu#open()
else
call quickui#menu#open(argv[0])
endif
endfunc
let s:quickui.menu = {
\ 'run': function('s:sub_menu'),
\ 'help': 'open main menu',
\ }
"----------------------------------------------------------------------
" sub: context menu
"----------------------------------------------------------------------
function! s:sub_context(opts, argv) abort
let context = []
if exists('g:quickui_context')
for item in g:quickui_context
let context += [item]
endfor
endif
if exists('b:quickui_context')
if !empty(context)
let context += ['--']
endif
for item in b:quickui_context
let context += [item]
endfor
endif
if exists('g:quickui_context_foot')
if !empty(context)
let context += ['--']
endif
for item in g:quickui_context_foot
let context += [item]
endfor
endif
let opts = {}
if !empty(context)
call quickui#tools#clever_context('_', context, opts)
endif
endfunc
let s:quickui.context = {
\ 'run': function('s:sub_context'),
\ 'help': 'open context menu',
\ }
"----------------------------------------------------------------------
" sub: terminal
"----------------------------------------------------------------------
function! s:sub_terminal(opts, argv) abort
let cmd = a:opts.cmdline
" echom printf("cmd is '%s', type: %d", cmd, type(cmd))
" echom a:opts
return quickui#terminal#open(cmd, a:opts)
endfunc
let s:quickui.terminal = {
\ 'run': function('s:sub_terminal'),
\ 'help': 'open terminal window',
\ }

View File

@ -0,0 +1,315 @@
"======================================================================
"
" confirm.vim -
"
" Created by skywind on 2021/12/11
" Last Modified: 2021/12/13 22:07
"
"======================================================================
" vim: set ts=4 sw=4 tw=78 noet :
"----------------------------------------------------------------------
" build buttons
"----------------------------------------------------------------------
function! s:button_prepare(choices)
let choices = quickui#utils#text_list_normalize(a:choices)
let items = []
let index = 0
let max_size = 4
for choice in choices
let item = quickui#utils#item_parse(choice)
let item.index = index
let items += [item]
let width = item.text_width
let max_size = (max_size < width)? width : max_size
let index += 1
endfor
for item in items
let width = item.text_width
let pad1 = (max_size - width) / 2
let pad2 = max_size - width - pad1
" let pad1 += 1
" let pad2 += 1
let item.text = repeat(' ', pad1) . item.text . repeat(' ', pad2)
if item.key_pos >= 0
let item.key_pos += pad1
endif
let item.text_width = strwidth(item.text)
endfor
return items
endfunc
"----------------------------------------------------------------------
" synthesis button line
"----------------------------------------------------------------------
function! s:button_finalize(items, style)
let items = a:items
let final = ''
let start = 0
let index = len(a:items) - 1
for item in a:items
if 0
let text = ' ' . item.text . ' '
else
let text = '<' . item.text . '>'
endif
let item.offset = -1
let need = 0
if 0
let need = 1
let text = '[' . text . ']'
endif
if item.key_pos >= 0
let item.offset = start + 1 + item.key_pos + need
endif
let item.start = start
let item.endup = start + item.text_width + 2 + need * 2
let start += item.text_width + 2 + need * 2
let final .= text
if index > 0
let final .= ' '
let start += 2
endif
let index -= 1
endfor
return final
endfunc
"----------------------------------------------------------------------
" create highlight
"----------------------------------------------------------------------
function! s:hl_prepare(hwnd)
let hwnd = a:hwnd
let c1 = get(g:, 'quickui_button_color_on', 'QuickSel')
let c2 = get(g:, 'quickui_button_color_off', 'QuickBG')
let ck = get(g:, 'quickui_button_color_key', 'QuickKey')
let hwnd.color_on = c1
let hwnd.color_off = c2
let hwnd.color_on2 = 'QuickButtonOn2'
let hwnd.color_off2 = 'QuickButtonOff2'
call quickui#highlight#clear('QuickBUttonOn2')
call quickui#highlight#clear('QuickBUttonOff2')
if 0
call quickui#highlight#overlay('QuickButtonOn2', c1, ck)
call quickui#highlight#overlay('QuickButtonOff2', c2, ck)
else
call quickui#highlight#make_underline('QuickButtonOn2', c1)
call quickui#highlight#make_underline('QuickButtonOff2', c2)
endif
endfunc
"----------------------------------------------------------------------
" calculate requirements
"----------------------------------------------------------------------
function! s:init(text, choices, index, title)
let hwnd = {}
let hwnd.text = quickui#utils#text_list_normalize(a:text)
let hwnd.items = s:button_prepare(a:choices)
let hwnd.final = s:button_finalize(hwnd.items, 0)
let hwnd.index = a:index
let button = ''
let text_size = 40
for text in hwnd.text
let ts = strdisplaywidth(text)
let text_size = (text_size < ts)? ts : text_size
endfor
let limit = &columns * 80 / 100
let limit = get(g:, 'quickui_confirm_max_width', limit)
let text_size = (text_size < limit)? text_size : limit
let hwnd.btn_size = strdisplaywidth(hwnd.final)
let hwnd.text_size = text_size
let hwnd.w = (hwnd.btn_size > text_size)? hwnd.btn_size : text_size
let hwnd.h = len(hwnd.text) + 3
let hwnd.tw = hwnd.w + 4
let hwnd.th = hwnd.h + 4
let border = g:quickui#style#border
let opts = {}
let opts.w = hwnd.w
let opts.h = hwnd.h
let opts.border = get(g:, 'quickui_confirm_border', border)
let opts.center = 1
let opts.title = (a:title == '')? '' : (' ' . a:title . ' ')
let opts.padding = [1, 1, 1, 1]
let opts.button = 1
let opts.wrap = 1
let hwnd.opts = opts
let content = deepcopy(hwnd.text)
let content += [' ', ' ']
let hwnd.padding = hwnd.w - hwnd.btn_size
let content += [repeat(' ', hwnd.padding) . hwnd.final]
let hwnd.content = content
let hwnd.win = quickui#window#new()
let hwnd.keymap = quickui#utils#keymap()
let index = 1
for item in hwnd.items
if item.key_pos >= 0
let ch = tolower(item.key_char)
let hwnd.keymap[ch] = 'ACCEPT:' . index
endif
let index += 1
endfor
let hwnd.keymap['h'] = 'LEFT'
let hwnd.keymap['l'] = 'RIGHT'
call s:hl_prepare(hwnd)
return hwnd
endfunc
"----------------------------------------------------------------------
"
"----------------------------------------------------------------------
function! s:draw_button(hwnd, index)
let hwnd = a:hwnd
let item = hwnd.items[a:index]
let index = a:index
let win = hwnd.win
let top = hwnd.h - 1
let off = hwnd.padding
let x = item.start
let e = item.endup
if hwnd.index == index
let c1 = hwnd.color_on
let c2 = hwnd.color_on2
" let c1 = 'QuickSel'
else
let c1 = hwnd.color_off
let c2 = hwnd.color_off2
" let c1 = 'QuickBG'
" return
endif
if item.offset < 0
call win.syntax_region(c1, off + x, top, off + e, top)
else
let u = item.offset + off
call win.syntax_region(c1, off + x, top, u, top)
call win.syntax_region(c2, u, top, u + 1, top)
call win.syntax_region(c1, u + 1, top, off + e, top)
endif
endfunc
"----------------------------------------------------------------------
" render
"----------------------------------------------------------------------
function! s:render(hwnd)
let hwnd = a:hwnd
let win = hwnd.win
let off = hwnd.padding
let top = hwnd.h - 1
let index = 0
call win.syntax_begin(1)
for item in hwnd.items
call s:draw_button(hwnd, index)
let index += 1
endfor
" call win.syntax_region(ck, 12, 0, 13, 0)
call win.syntax_end()
endfunc
"----------------------------------------------------------------------
" main entry
"----------------------------------------------------------------------
function! quickui#confirm#open(text, ...)
let choices = (a:0 < 1)? " &OK " : (a:1)
let index = (a:0 < 2)? 1 : (a:2)
let title = (a:0 < 3)? 'Confirm' : (a:3)
let choices = (choices == '')? " &OK " : choices
let hwnd = s:init(a:text, choices, index - 1, title)
let win = hwnd.win
let accept = 0
let size = len(hwnd.items)
if size == 0
return 0
endif
if has('nvim')
let hwnd.opts.focusable = 1
endif
call win.open(hwnd.content, hwnd.opts)
while 1
call s:render(hwnd)
redraw
let ch = quickui#utils#getchar(1)
if ch == "\<c-c>" || ch == "\<esc>"
let accept = 0
break
elseif ch == "\<space>" || ch == "\<cr>"
let accept = hwnd.index + 1
break
elseif win.quit != 0
let accept = 0
break
elseif ch == "\<LeftMouse>"
if has('nvim') == 0
let pos = getmousepos()
let x = pos.column - 1
let y = pos.line - 1
else
let x = v:mouse_col - 1
let y = v:mouse_lnum - 1
endif
if v:mouse_winid == win.winid
if y == hwnd.h - 1 && x >= hwnd.padding
let u = x - hwnd.padding
for item in hwnd.items
if u >= item.start && u < item.endup
let accept = item.index + 1
break
endif
endfor
if accept > 0
break
endif
endif
elseif v:mouse_winid == win.info.border_winid
if y == 0 && x == win.info.tw - 1
let accept = 0
break
endif
endif
else
let key = get(hwnd.keymap, ch, ch)
if key == 'LEFT'
let hwnd.index = (hwnd.index > 0)? (hwnd.index - 1) : 0
elseif key == 'RIGHT'
if hwnd.index < size - 1
let hwnd.index += 1
endif
elseif key == 'HOME' || key == 'UP' || key == 'PAGEUP'
let hwnd.index = 0
elseif key == 'END' || key == 'DOWN' || key == 'PAGEDOWN'
let hwnd.index = size - 1
elseif key =~ '^ACCEPT:'
let key = strpart(key, 7)
let index = str2nr(key)
if index > 0 && index <= size
let accept = index
break
endif
endif
endif
endwhile
if accept > 0 && win.quit == 0
let hwnd.index = accept - 1
call s:render(hwnd)
redraw
sleep 15m
endif
call win.close()
return accept
endfunc

View File

@ -0,0 +1,930 @@
"======================================================================
"
" context.vim -
"
" Created by skywind on 2019/12/19
" Last Modified: 2022/08/24 20:05
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" stats
"----------------------------------------------------------------------
" last position
let g:quickui#context#cursor = -1
"----------------------------------------------------------------------
" compile
"----------------------------------------------------------------------
function! quickui#context#compile(items, border)
let menu = {'border':a:border}
let items = []
let helps = []
let size_l = 0
let size_r = 0
let index = 0
let helps = 0
for item in a:items
let ni = quickui#utils#item_parse(item)
let ni.index = index
let items += [ni]
let index += 1
if ni.help != ''
let helps += 1
endif
" echo ni
if ni.text_width > size_l
let size_l = ni.text_width
endif
if ni.desc_width > size_r
let size_r = ni.desc_width
endif
endfor
let stride = size_l + size_r + ((size_r > 0)? 2 : 0)
for item in items
call quickui#utils#context_align(item, size_l, size_r)
endfor
let menu.items = items
let menu.helps = helps
let image = []
if a:border <= 0
for item in items
let image += [item.content]
endfor
else
let pattern = quickui#core#border_get(a:border)
let text = pattern[0] . repeat(pattern[1], stride + 2) . pattern[2]
let image += [text]
for item in items
if item.is_sep
let text = pattern[9] . repeat(pattern[4], stride + 2) . pattern[10]
let image += [text]
else
let text = pattern[3] . ' ' . item.content . ' ' . pattern[5]
let image += [text]
endif
endfor
let text = pattern[6] . repeat(pattern[7], stride + 2) . pattern[8]
let image += [text]
endif
let menu.image = image
let menu.border = a:border
let menu.height = len(image)
let menu.width = (menu.height > 0)? strwidth(image[0]) : 0
let menu.selected = -1
let menu.size = len(items)
let menu.exiting = 0
let menu.state = 0
let selection = []
for item in menu.items
if item.is_sep == 0
let selection += [item.index]
endif
endfor
let menu.selection = selection
return menu
endfunc
"----------------------------------------------------------------------
" create menu object
"----------------------------------------------------------------------
function! s:vim_create_context(textlist, opts)
let border = get(a:opts, 'border', g:quickui#style#border)
let hwnd = quickui#context#compile(a:textlist, border)
if 0
let hwnd.bid = quickui#core#scratch_buffer('context', hwnd.image)
let winid = popup_create(hwnd.bid, {'hidden':1, 'wrap':0})
else
let winid = popup_create(hwnd.image, {'hidden':1, 'wrap':0})
endif
let w = hwnd.width
let h = hwnd.height
let hwnd.winid = winid
let hwnd.index = get(a:opts, 'index', -1)
let hwnd.opts = deepcopy(a:opts)
let ignore_case = get(a:opts, 'ignore_case', 1)
let opts = {'minwidth':w, 'maxwidth':w, 'minheight':h, 'maxheight':h}
if has_key(a:opts, 'line') && has_key(a:opts, 'col')
let opts.line = a:opts.line
let opts.col = a:opts.col
else
let pos = quickui#core#around_cursor(w, h)
let opts.line = pos[0]
let opts.col = pos[1]
endif
call popup_move(winid, opts)
call setwinvar(winid, '&wincolor', get(a:opts, 'color', 'QuickBG'))
let opts = {'cursorline':0, 'drag':0, 'mapping':0}
let opts.border = [0,0,0,0,0,0,0,0,0]
let opts.title = has_key(a:opts, 'title')? ' ' . a:opts.title . ' ' : ''
let opts.padding = [0,0,0,0]
let keymap = quickui#utils#keymap()
let keymap['J'] = 'BOTTOM'
let keymap['K'] = 'TOP'
if has_key(a:opts, 'keymap')
for key in keys(a:opts.keymap)
let keymap[key] = a:opts.keymap[key]
endfor
endif
let hwnd.code = 0
let hwnd.state = 1
let hwnd.keymap = keymap
let hwnd.hotkey = {}
for item in hwnd.items
if item.enable != 0 && item.key_pos >= 0
let key = ignore_case ? tolower(item.key_char) : item.key_char
if get(a:opts, 'reserve', 0) == 0
let hwnd.hotkey[key] = item.index
elseif get(g:, 'quickui_protect_hjkl', 0) != 0
let hwnd.hotkey[key] = item.index
else
if key != 'h' && key != 'j' && key != 'k' && key != 'l'
let hwnd.hotkey[key] = item.index
endif
endif
endif
endfor
let local = quickui#core#popup_local(winid)
let local.hwnd = hwnd
if get(a:opts, 'manual', 0) == 0
let opts.callback = function('s:popup_exit')
let opts.filter = function('s:popup_filter')
endif
if has_key(a:opts, 'zindex')
let opts.zindex = a:opts.zindex
endif
call popup_setoptions(winid, opts)
call quickui#context#update(hwnd)
call popup_show(winid)
return hwnd
endfunc
"----------------------------------------------------------------------
" render menu
"----------------------------------------------------------------------
function! quickui#context#update(hwnd)
let winid = a:hwnd.winid
let size = len(a:hwnd.items)
let w = a:hwnd.width
let h = a:hwnd.height
let cmdlist = ['syn clear']
for item in a:hwnd.items
let index = item.index
if item.enable == 0 && item.is_sep == 0
if a:hwnd.border == 0
let py = index + 1
let px = 1
let ps = px + w
else
let py = index + 2
let px = 3
let ps = px + w - 4
endif
let cmd = quickui#core#high_region('QuickOff', py, px, py, ps, 1)
let cmdlist += [cmd]
elseif item.key_pos >= 0
if a:hwnd.border == 0
let px = item.key_pos + 1
let py = index + 1
else
let px = item.key_pos + 3
let py = index + 2
endif
let ps = px + 1
let cmd = quickui#core#high_region('QuickKey', py, px, py, ps, 1)
let cmdlist += [cmd]
endif
if index == a:hwnd.index
if a:hwnd.border == 0
let py = index + 1
let px = 1
let ps = px + w
else
let py = index + 2
let px = 2
let ps = px + w - 2
endif
let cmd = quickui#core#high_region('QuickSel', py, px, py, ps, 1)
let cmdlist += [cmd]
endif
endfor
call quickui#core#win_execute(winid, cmdlist)
if a:hwnd.state != 0
redraw
if get(g:, 'quickui_show_tip', 0) != 0
let help = ''
if a:hwnd.index >= 0 && a:hwnd.index < len(a:hwnd.items)
let help = a:hwnd.items[a:hwnd.index].help
let head = g:quickui#style#tip_head
if help != ''
let help = quickui#core#expand_text(help)
let help = '' . ((head != '')? (head . ' ') : '') . help
endif
endif
echohl QuickHelp
echo help
echohl None
endif
endif
endfunc
"----------------------------------------------------------------------
" close context
"----------------------------------------------------------------------
function! quickui#context#close(hwnd)
if a:hwnd.winid > 0
call popup_close(a:hwnd.winid)
call quickui#core#popup_clear(a:hwnd.winid)
let a:hwnd.winid = -1
endif
endfunc
"----------------------------------------------------------------------
" handle exit code
"----------------------------------------------------------------------
function! s:popup_exit(winid, code)
let local = quickui#core#popup_local(a:winid)
if !has_key(local, 'hwnd')
return 0
endif
let hwnd = local.hwnd
let code = a:code
let hwnd.state = 0
let hwnd.code = code
call quickui#core#popup_clear(a:winid)
if get(g:, 'quickui_show_tip', 0) != 0
if get(hwnd.opts, 'lazyredraw', 0) == 0
redraw
echo ''
redraw
endif
endif
let g:quickui#context#code = code
let g:quickui#context#current = hwnd
let g:quickui#context#cursor = hwnd.index
let redrawed = 0
if has_key(hwnd.opts, 'callback')
call call(hwnd.opts.callback, [code])
endif
silent! call popup_hide(a:winid)
if code >= 0 && code < len(hwnd.items)
let item = hwnd.items[code]
if item.is_sep == 0 && item.enable != 0
if item.cmd != ''
redraw
try
exec item.cmd
catch /.*/
echohl Error
echom v:exception
echohl None
endtry
endif
endif
endif
return 0
endfunc
"----------------------------------------------------------------------
" key processing
"----------------------------------------------------------------------
function! s:popup_filter(winid, key)
let local = quickui#core#popup_local(a:winid)
let hwnd = local.hwnd
let winid = hwnd.winid
if a:key == "\<ESC>" || a:key == "\<c-c>"
call popup_close(a:winid, -1)
return 1
elseif a:key == "\<CR>" || a:key == "\<SPACE>"
call s:on_confirm(hwnd)
return 1
elseif a:key == "\<LeftMouse>"
return s:on_click(hwnd)
elseif has_key(hwnd.hotkey, a:key)
let key = hwnd.hotkey[a:key]
if key >= 0 && key < len(hwnd.items)
let item = hwnd.items[key]
if item.is_sep == 0 && item.enable != 0
let hwnd.index = key
call quickui#context#update(hwnd)
call popup_setoptions(winid, {})
redraw
call popup_close(winid, key)
return 1
endif
endif
elseif has_key(hwnd.keymap, a:key)
let key = hwnd.keymap[a:key]
if key == 'ESC'
call popup_close(a:winid, -1)
return 1
elseif key == 'UP'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, -1)
elseif key == 'DOWN'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 1)
elseif key == 'TOP'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 'TOP')
elseif key == 'BOTTOM'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 'BOTTOM')
endif
if get(hwnd.opts, 'horizon', 0) != 0
if key == 'LEFT'
call popup_close(a:winid, -1000)
elseif key == 'RIGHT'
call popup_close(a:winid, -2000)
elseif key == 'PAGEUP'
call popup_close(a:winid, -1001)
elseif key == 'PAGEDOWN'
call popup_close(a:winid, -2001)
endif
endif
call quickui#context#update(hwnd)
return 1
endif
return 1
endfunc
"----------------------------------------------------------------------
" press enter or space
"----------------------------------------------------------------------
function! s:on_confirm(hwnd)
let index = a:hwnd.index
if index < 0 || index > len(a:hwnd.items)
return 1
endif
let item = a:hwnd.items[index]
if item.is_sep || item.enable == 0
return 1
endif
call popup_close(a:hwnd.winid, index)
return 1
endfunc
"----------------------------------------------------------------------
" mouse left click
"----------------------------------------------------------------------
function! s:on_click(hwnd)
let hwnd = a:hwnd
let winid = a:hwnd.winid
if g:quickui#core#has_nvim == 0
let pos = getmousepos()
if pos.winid != winid
call popup_close(winid, -2)
return 0
endif
let index = -1
if hwnd.border == 0
let index = pos.line - 1
else
if pos.column > 1 && pos.column < hwnd.width
if pos.line > 1 && pos.line < hwnd.height
let index = pos.line - 2
endif
endif
endif
if index >= 0 && index < len(hwnd.items)
let item = hwnd.items[index]
if item.is_sep == 0 && item.enable != 0
let hwnd.index = index
call quickui#context#update(hwnd)
call popup_setoptions(winid, {})
redraw
call popup_close(winid, index)
endif
endif
return 1
else
if v:mouse_winid != winid
return -2
endif
let index = -1
if hwnd.border == 0
let index = v:mouse_lnum - 1
else
if v:mouse_col > 1 && v:mouse_col < hwnd.width
if v:mouse_lnum > 1 && v:mouse_lnum < hwnd.height
let index = v:mouse_lnum - 2
endif
endif
endif
if index >= 0 && index < len(hwnd.items)
let item = hwnd.items[index]
if item.is_sep == 0 && item.enable != 0
let hwnd.index = index
call quickui#context#update(hwnd)
redraw
sleep 60m
return index
endif
endif
return -1
endif
endfunc
"----------------------------------------------------------------------
" move cursor
"----------------------------------------------------------------------
function! s:cursor_move(menu, cursor, toward)
let size = a:menu.size
if type(a:toward) == v:t_number
if a:toward == 0
if size <= 0
return -1
elseif a:cursor < 0
return a:cursor
endif
return (a:cursor >= size)? (size - 1) : a:cursor
endif
endif
let selection = a:menu.selection
if size == 0 || len(selection) == 0
return -1
endif
let cursor = a:cursor + a:toward
if type(a:toward) == v:t_number
if a:toward < 0
if a:cursor < 0
return selection[0]
endif
let cursor = (cursor < 0)? 0 : cursor
let pos = len(selection) - 1
while pos >= 0
if selection[pos] <= cursor
return selection[pos]
endif
let pos -= 1
endwhile
return selection[0]
else
let pos = 0
let limit = len(selection)
while pos < limit
if selection[pos] >= cursor
return selection[pos]
endif
let pos += 1
endwhile
return selection[limit - 1]
endif
else
if a:toward == 'TOP'
return selection[0]
elseif a:toward == 'BOTTOM'
return selection[-1]
endif
endif
return -1
endfunc
"----------------------------------------------------------------------
" open context menu in neovim and returns index
"----------------------------------------------------------------------
function! s:nvim_create_context(textlist, opts)
let border = get(a:opts, 'border', g:quickui#style#border)
let ignore_case = get(a:opts, 'ignore_case', 1)
let hwnd = quickui#context#compile(a:textlist, border)
let bid = quickui#core#scratch_buffer('context', hwnd.image)
let hwnd.bid = bid
let w = hwnd.width
let h = hwnd.height
let hwnd.index = get(a:opts, 'index', -1)
let hwnd.opts = deepcopy(a:opts)
let opts = {'width':w, 'height':h, 'focusable':1, 'style':'minimal'}
let opts.relative = 'editor'
if has_key(a:opts, 'line') && has_key(a:opts, 'col')
let opts.row = a:opts.line - 1
let opts.col = a:opts.col - 1
else
let pos = quickui#core#around_cursor(w, h)
let opts.row = pos[0] - 1
let opts.col = pos[1] - 1
endif
if has('nvim-0.6.0')
let opts.noautocmd = 1
endif
let winid = nvim_open_win(bid, 0, opts)
let hwnd.winid = winid
let keymap = quickui#utils#keymap()
let keymap['J'] = 'BOTTOM'
let keymap['K'] = 'TOP'
let hwnd.code = 0
let hwnd.state = 1
let hwnd.keymap = keymap
let hwnd.hotkey = {}
for item in hwnd.items
if item.enable != 0 && item.key_pos >= 0
let key = ignore_case ? tolower(item.key_char) : item.key_char
if get(a:opts, 'reserve', 0) == 0
let hwnd.hotkey[key] = item.index
elseif get(g:, 'quickui_protect_hjkl', 0) != 0
let hwnd.hotkey[key] = item.index
else
if key != 'h' && key != 'j' && key != 'k' && key != 'l'
let hwnd.hotkey[key] = item.index
endif
endif
endif
endfor
let hwnd.opts.color = get(a:opts, 'color', 'QuickBG')
call nvim_win_set_option(winid, 'winhl', 'Normal:'. hwnd.opts.color)
let retval = -1
while 1
noautocmd call quickui#context#update(hwnd)
redraw
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<ESC>" || ch == "\<c-c>"
break
elseif ch == " " || ch == "\<cr>"
let index = hwnd.index
if index >= 0 && index < len(hwnd.items)
let item = hwnd.items[index]
if item.is_sep == 0 && item.enable != 0
let retval = index
break
endif
endif
elseif ch == "\<LeftMouse>"
let hr = s:on_click(hwnd)
if hr == -2 || hr >= 0
let retval = hr
break
endif
elseif has_key(hwnd.hotkey, ch)
let hr = hwnd.hotkey[ch]
if hr >= 0
let hwnd.index = hr
let retval = hr
break
endif
elseif has_key(hwnd.keymap, ch)
let key = hwnd.keymap[ch]
if key == 'ESC'
break
elseif key == 'UP'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, -1)
elseif key == 'DOWN'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 1)
elseif key == 'TOP'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 'TOP')
elseif key == 'BOTTOM'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 'BOTTOM')
endif
if get(hwnd.opts, 'horizon', 0) != 0
if key == 'LEFT'
let retval = -1000
break
elseif key == 'RIGHT'
let retval = -2000
break
elseif key == 'PAGEUP'
let retval = -1001
break
elseif key == 'PAGEDOWN'
let retval = -2001
break
endif
endif
endif
endwhile
call nvim_win_close(winid, 0)
if get(a:opts, 'lazyredraw', 0) == 0
redraw
endif
if get(g:, 'quickui_show_tip', 0) != 0
if get(a:opts, 'lazyredraw', 0) == 0
echo ''
redraw
endif
endif
let g:quickui#context#code = retval
let g:quickui#context#current = hwnd
let g:quickui#context#cursor = hwnd.index
if has_key(hwnd.opts, 'callback')
call call(hwnd.opts.callback, [retval])
endif
if retval >= 0 && retval < len(hwnd.items)
let item = hwnd.items[retval]
if item.is_sep == 0 && item.enable != 0
if item.cmd != ''
redraw
try
exec item.cmd
catch /.*/
echohl Error
echom v:exception
echohl None
endtry
endif
endif
endif
return retval
endfunc
"----------------------------------------------------------------------
" reduce with file types
"----------------------------------------------------------------------
function! quickui#context#reduce_items(textlist)
let output = []
let state = 1
let index = 0
let limit = len(a:textlist)
for item in a:textlist
if len(item) > 0
let issep = ((item[0]) =~ '^-\+$')? 1 : 0
if issep != 0
if state == 0
if index + 1 < limit
let output += [item]
let state = 1
endif
endif
else
if type(item) == v:t_string
let output += [item]
let state = 0
elseif len(item) < 4
let output += [item]
let state = 0
else
if quickui#utils#match_ft(&ft, item[3])
let output += [item]
let state = 0
endif
endif
endif
endif
let index += 1
endfor
return output
endfunc
"----------------------------------------------------------------------
" create menu object
"----------------------------------------------------------------------
function! quickui#context#open(textlist, opts)
let textlist = a:textlist
if g:quickui#core#has_nvim == 0
return s:vim_create_context(textlist, a:opts)
else
return s:nvim_create_context(textlist, a:opts)
endif
endfunc
"----------------------------------------------------------------------
" open the context window and wait for selection
"----------------------------------------------------------------------
function! s:context_wait(textlist, opts) abort
let border = get(a:opts, 'border', g:quickui#style#border)
let ignore_case = get(a:opts, 'ignore_case', 1)
let hwnd = quickui#context#compile(a:textlist, border)
let cwnd = quickui#window#new()
let w = hwnd.width
let h = hwnd.height
let hwnd.index = get(a:opts, 'index', -1)
let hwnd.opts = a:opts
let opts = {'w':w, 'h':h, 'border':0}
if has_key(a:opts, 'x') && has_key(a:opts, 'y')
let opts.x = a:opts.x
let opts.y = a:opts.y
else
let pos = quickui#core#around_cursor(w, h)
let opts.y = pos[0] - 1
let opts.x = pos[1] - 1
endif
let opts.z = get(a:opts, 'z', 500)
let opts.color = get(a:opts, 'color', 'QuickBG')
let hwnd.direct = get(a:opts, 'direct', 0)
if hwnd.direct == 0
let hwnd.direct = (opts.x <= (&columns / 2))? 1 : -1
endif
call cwnd.open(hwnd.image, opts)
call cwnd.show(1)
let keymap = quickui#utils#keymap()
let keymap['J'] = 'BOTTOM'
let keymap['K'] = 'TOP'
let hwnd.code = 0
let hwnd.state = 1
let hwnd.keymap = keymap
let hwnd.hotkey = {}
for item in hwnd.items
if item.enable != 0 && item.key_pos >= 0
let key = ignore_case ? tolower(item.key_char) : item.key_char
if get(a:opts, 'reserve', 0) == 0
let hwnd.hotkey[key] = item.index
elseif get(g:, 'quickui_protect_hjkl', 0) != 0
let hwnd.hotkey[key] = item.index
else
if key != 'h' && key != 'j' && key != 'k' && key != 'l'
let hwnd.hotkey[key] = item.index
endif
endif
endif
endfor
let hwnd.winid = cwnd.winid
let retval = -1
while 1
noautocmd call quickui#context#update(hwnd)
redraw
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<ESC>" || ch == "\<c-c>"
break
elseif ch == " " || ch == "\<cr>"
let index = hwnd.index
if index >= 0 && index < len(hwnd.items)
let item = hwnd.items[index]
if item.is_sep == 0 && item.enable != 0
let retval = index
break
endif
endif
elseif ch == "\<LeftMouse>"
let pos = cwnd.mouse_click()
if pos.x < 0
break
else
let x1 = (hwnd.border == 0)? 0 : 1
let x2 = (hwnd.border == 0)? w : (w - 1)
let ii = (hwnd.border == 0)? pos.y : (pos.y - 1)
if pos.x >= x1 && pos.x < x2
if ii >= 0 && ii < len(hwnd.items)
let item = hwnd.items[ii]
if item.is_sep == 0 && item.enable != 0
let hwnd.index = ii
let retval = ii
noautocmd call quickui#context#update(hwnd)
redraw
break
endif
endif
endif
endif
elseif has_key(hwnd.hotkey, ch)
let hr = hwnd.hotkey[ch]
if hr >= 0
let hwnd.index = hr
let retval = hr
break
endif
elseif has_key(hwnd.keymap, ch)
let key = hwnd.keymap[ch]
if key == 'ESC'
break
elseif key == 'UP'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, -1)
elseif key == 'DOWN'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 1)
elseif key == 'TOP'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 'TOP')
elseif key == 'BOTTOM'
let hwnd.index = s:cursor_move(hwnd, hwnd.index, 'BOTTOM')
endif
endif
endwhile
noautocmd call quickui#context#update(hwnd)
let hr = ''
if retval >= 0 && retval < len(hwnd.items)
let item = hwnd.items[retval]
if item.is_sep == 0 && item.enable != 0
let hwnd.index = retval
if !has_key(item, 'child')
let hr = item.cmd
else
let child = item.child
let cc = quickui#context#compile(child, border)
let cw = cc.width
let ch = cc.height
unlet cc
let op = {}
let op.z = opts.z + 1
let op.y = opts.y + retval
let op.y = (op.y + ch > &lines)? (&lines - ch) : op.y
let op.y = (op.y < 0)? 0 : op.y
for i in range(5)
if hwnd.direct >= 0
let tx = opts.x + opts.w
if tx + cw > &columns
let hwnd.direct = -1
else
let op.x = tx
break
endif
elseif hwnd.direct < 0
let tx = opts.x - cw
if tx < 0
let hwnd.direct = 1
else
let op.x = tx
break
endif
endif
endfor
if !has_key(op, 'x')
let op.x = 1
endif
let op.direct = hwnd.direct
let op.border = get(a:opts, 'border', border)
let hr = s:context_wait(child, op)
endif
endif
endif
let g:quickui#context#cursor = hwnd.index
let g:quickui#context#current = hwnd
call cwnd.close()
unlet cwnd
return hr
endfunc
"----------------------------------------------------------------------
" open the context window and wait for selection
"----------------------------------------------------------------------
function! quickui#context#wait(textlist, opts) abort
return s:context_wait(a:textlist, a:opts)
endfunc
"----------------------------------------------------------------------
" open context menu and execute commands
"----------------------------------------------------------------------
function! quickui#context#open_nested(textlist, opts) abort
let cmd = s:context_wait(a:textlist, a:opts)
if has_key(a:opts, 'callback')
call a:opts.callback(0)
endif
if cmd != ''
exec cmd
endif
endfunc
"----------------------------------------------------------------------
" testing suit
"----------------------------------------------------------------------
if 0
call quickui#utils#highlight('default')
let lines = [
\ "&New File\tCtrl+n",
\ "&Open File\tCtrl+o",
\ ["&Close", 'echo 1234', 'help 1'],
\ "--",
\ "&Save\tCtrl+s",
\ "Save &As",
\ "Save All",
\ "--",
\ "&User Menu\tF9",
\ "&Dos Shell",
\ "~&Time %{&undolevels? '+':'-'}",
\ ["S&plit", 'help 1', '', 'vim2'],
\ "--",
\ "E&xit\tAlt+x",
\ "&Help",
\ ]
" echo quickui#core#pattern_ascii
" let menu = quickui#context#menu_compile(lines, 1)
let opts = {'cursor': -1, 'line2':'cursor+1', 'col2': 'cursor', 'horizon':1}
" let opts.index = 2
let opts.savepos = 'f'
let opts.callback = 'MyCallback'
let opts.reduce = 1
function! MyCallback(code)
echom "callback: " . a:code
endfunc
if 1
let menu = quickui#context#open(lines, opts)
" echo menu
else
let item = quickui#utils#item_parse("你好吗f&aha\tAlt+x")
echo item
endif
endif

View File

@ -0,0 +1,925 @@
"======================================================================
"
" core.vim -
"
" Created by skywind on 2019/12/18
" Last Modified: 2022/08/31 16:25
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"======================================================================
" core routines
"======================================================================
"----------------------------------------------------------------------
" global variables
"----------------------------------------------------------------------
let g:quickui#core#has_nvim = has('nvim')
let g:quickui#core#has_vim9 = v:version >= 900
let g:quickui#core#has_popup = exists('*popup_create') && v:version >= 800
let g:quickui#core#has_floating = has('nvim-0.4')
let g:quickui#core#has_nvim_040 = has('nvim-0.4')
let g:quickui#core#has_nvim_050 = has('nvim-0.5.0')
let g:quickui#core#has_nvim_060 = has('nvim-0.6.0')
let g:quickui#core#has_vim_820 = (has('nvim') == 0 && has('patch-8.2.1'))
let g:quickui#core#has_win_exe = exists('*win_execute')
let g:quickui#core#has_vim9script = (v:version >= 900) && has('vim9script')
"----------------------------------------------------------------------
" internal variables
"----------------------------------------------------------------------
let s:windows = has('win32') || has('win16') || has('win64') || has('win95')
"----------------------------------------------------------------------
" object pool acquire
"----------------------------------------------------------------------
function! quickui#core#object_acquire(name)
if !exists('g:quickui#core#__object_pool__')
let g:quickui#core#__object_pool__ = {}
endif
if !has_key(g:quickui#core#__object_pool__, a:name)
let g:quickui#core#__object_pool__[a:name] = []
endif
let array = g:quickui#core#__object_pool__[a:name]
if len(array) == 0
return v:null
endif
let obj = remove(array, -1)
return obj
endfunc
"----------------------------------------------------------------------
" object pool release
"----------------------------------------------------------------------
function! quickui#core#object_release(name, obj)
if !exists('g:quickui#core#__object_pool__')
let g:quickui#core#__object_pool__ = {}
endif
if !has_key(g:quickui#core#__object_pool__, a:name)
let g:quickui#core#__object_pool__[a:name] = []
endif
call add(g:quickui#core#__object_pool__[a:name], a:obj)
endfunc
"----------------------------------------------------------------------
" replace string
"----------------------------------------------------------------------
function! quickui#core#string_replace(text, old, new)
let l:data = split(a:text, a:old, 1)
return join(l:data, a:new)
endfunc
"----------------------------------------------------------------------
" compose two string
"----------------------------------------------------------------------
function! quickui#core#string_compose(target, pos, source)
if a:source == ''
return a:target
endif
let pos = a:pos
let source = a:source
if pos < 0
let source = strcharpart(a:source, -pos)
let pos = 0
endif
let target = strcharpart(a:target, 0, pos)
if strchars(target) < pos
let target .= repeat(' ', pos - strchars(target))
endif
let target .= source
let target .= strcharpart(a:target, pos + strchars(source))
return target
endfunc
"----------------------------------------------------------------------
" fit size
"----------------------------------------------------------------------
function! quickui#core#string_fit(source, size)
let require = a:size
let source = a:source
let size = len(source)
if size <= require
return source
endif
if require <= 2
return repeat('.', (require < 0)? 0 : require)
endif
let avail = require - 2
let left = avail / 2
let right = avail - left
let p1 = strpart(source, 0, left)
let p2 = strpart(source, size - right)
let text = p1 . '..' . p2
return text
endfunc
"----------------------------------------------------------------------
" eval & expand: '%{script}' in string
"----------------------------------------------------------------------
function! quickui#core#expand_text(string) abort
let partial = []
let index = 0
while 1
let pos = stridx(a:string, '%{', index)
if pos < 0
let partial += [strpart(a:string, index)]
break
endif
let head = ''
if pos > index
let partial += [strpart(a:string, index, pos - index)]
endif
let endup = stridx(a:string, '}', pos + 2)
if endup < 0
let partial += [strpart(a:stirng, index)]
break
endif
let index = endup + 1
if endup > pos + 2
let script = strpart(a:string, pos + 2, endup - (pos + 2))
let script = substitute(script, '^\s*\(.\{-}\)\s*$', '\1', '')
let result = eval(script)
let partial += [result]
endif
endwhile
return join(partial, '')
endfunc
"----------------------------------------------------------------------
" escape key character (starts by &) from string
"----------------------------------------------------------------------
function! quickui#core#escape(text)
let text = a:text
let rest = ''
let start = 0
let obj = ['', '', -1, -1, -1]
while 1
let pos = stridx(text, '&', start)
if pos < 0
let rest .= strpart(text, start)
break
end
let rest .= strpart(text, start, pos - start)
let key = strpart(text, pos + 1, 1)
let start = pos + 2
if key == '&'
let rest .= '&'
elseif key == '~'
let rest .= '~'
else
let obj[1] = key
let obj[2] = strlen(rest)
let obj[3] = strchars(rest)
let obj[4] = strdisplaywidth(rest)
let rest .= key
endif
endwhile
let obj[0] = rest
return obj
endfunc
"----------------------------------------------------------------------
" list parse
"----------------------------------------------------------------------
function! quickui#core#single_parse(description)
let item = { 'part': [], 'size': 0 }
let item.key_char = ''
let item.key_pos = -1
let item.key_idx = -1
if type(a:description) == v:t_string
let text = a:description
let item.cmd = ''
elseif type(a:description) == v:t_list
let size = len(a:description)
let text = (size > 0)? a:description[0] : ''
let item.cmd = (size > 1)? a:description[1] : ''
endif
for text in split(text, "\t")
let obj = quickui#core#escape(text)
let item.part += [obj[0]]
if obj[2] >= 0 && item.key_idx < 0
let item.key_char = obj[1]
let item.key_pos = obj[4]
let item.key_idx = item.size
endif
let item.size += 1
endfor
return item
endfunc
"----------------------------------------------------------------------
" tabpage instance
"----------------------------------------------------------------------
function! quickui#core#instance(local)
let local = a:local
if local != 0
if exists('t:__quickui__')
return t:__quickui__
endif
let t:__quickui__ = {}
return t:__quickui__
else
if exists('g:__quickui__')
return g:__quickui__
endif
let g:__quickui__ = {}
return g:__quickui__
endif
endfunc
"----------------------------------------------------------------------
" buffer instance
"----------------------------------------------------------------------
function! quickui#core#object(bid)
let name = '__quickui__'
let bid = (a:bid > 0)? a:bid : (bufnr())
if bufexists(bid) == 0
return v:null
endif
let obj = getbufvar(bid, name)
if type(obj) != v:t_dict
call setbufvar(bid, name, {})
let obj = getbufvar(bid, name)
endif
return obj
endfunc
"----------------------------------------------------------------------
" object cache: acquire
"----------------------------------------------------------------------
function! quickui#core#popup_alloc(name)
let inst = quickui#core#instance(1)
if !has_key(inst, 'popup_cache')
let inst.popup_cache = {}
endif
if !has_key(inst.popup_cache, a:name)
let inst.popup_cache[a:name] = []
endif
if !empty(inst.popup_cache[a:name])
let winid = remove(inst.popup_cache[a:name], -1)
return winid
endif
let opts = {"line":1, "col":1, "wrap":0, "pos": 'topleft'}
let winid = popup_create([], opts)
call popup_hide(winid)
call win_execute(winid, 'setlocal nonumber nowrap signcolumn=no')
call setwinvar(winid, '&wincolor', 'QuickBG')
return winid
endfunc
"----------------------------------------------------------------------
" object cache: release
"----------------------------------------------------------------------
function! quickui#core#popup_release(name, winid)
let inst = quickui#core#instance(1)
if !has_key(inst, 'popup_cache')
let inst.popup_cache = {}
endif
if !has_key(inst.popup_cache, a:name)
let inst.popup_cache[a:name] = []
endif
silent! call popup_hide(a:winid)
let size = len(inst.popup_cache[a:name])
call insert(inst.popup_cache[a:name], a:winid, size)
endfunc
"----------------------------------------------------------------------
" local object
"----------------------------------------------------------------------
function! quickui#core#popup_local(winid)
let inst = quickui#core#instance(0)
if !has_key(inst, 'popup_local')
let inst.popup_local = {}
endif
if !has_key(inst.popup_local, a:winid)
let inst.popup_local[a:winid] = {}
endif
return inst.popup_local[a:winid]
endfunc
"----------------------------------------------------------------------
" erase local data
"----------------------------------------------------------------------
function! quickui#core#popup_clear(winid)
let inst = quickui#core#instance(0)
if !has_key(inst, 'popup_local')
let inst.popup_local = {}
endif
if has_key(inst.popup_local, a:winid)
call remove(inst.popup_local, a:winid)
endif
endfunc
"----------------------------------------------------------------------
" vim/nvim compatible
"----------------------------------------------------------------------
function! quickui#core#win_execute(winid, command, ...)
let silent = (a:0 < 1)? 0 : (a:1)
if g:quickui#core#has_popup != 0
if type(a:command) == v:t_string
keepalt call win_execute(a:winid, a:command, silent)
elseif type(a:command) == v:t_list
keepalt call win_execute(a:winid, join(a:command, "\n"), silent)
endif
elseif g:quickui#core#has_win_exe == 0
let current = nvim_get_current_win()
keepalt call nvim_set_current_win(a:winid)
if type(a:command) == v:t_string
if silent == 0
exec a:command
else
silent exec a:command
endif
elseif type(a:command) == v:t_list
if silent == 0
exec join(a:command, "\n")
else
silent exec join(a:command, "\n")
endif
endif
keepalt call nvim_set_current_win(current)
else
if type(a:command) == v:t_string
keepalt call win_execute(a:winid, a:command, silent)
elseif type(a:command) == v:t_list
keepalt call win_execute(a:winid, join(a:command, "\n"), silent)
endif
endif
endfunc
"----------------------------------------------------------------------
" close window
"----------------------------------------------------------------------
function! quickui#core#win_close(winid, force)
let [tnr, wnr] = win_id2tabwin(a:winid)
if tnr <= 0 || wnr <= 0
return -1
endif
if g:quickui#core#has_nvim == 0
let cmd = 'close' . ((a:force != 0)? '!' : '')
call quickui#core#win_execute(a:winid, cmd)
else
call nvim_win_close(a:winid, a:force)
endif
return 0
endfunc
"----------------------------------------------------------------------
" alloc a new buffer
"----------------------------------------------------------------------
function! quickui#core#buffer_alloc()
if !exists('s:buffer_array')
let s:buffer_array = {}
endif
let index = len(s:buffer_array) - 1
if index >= 0
let bid = s:buffer_array[index]
unlet s:buffer_array[index]
else
if g:quickui#core#has_nvim == 0
let bid = bufadd('')
call bufload(bid)
call setbufvar(bid, '&buflisted', 0)
call setbufvar(bid, '&bufhidden', 'hide')
call setbufvar(bid, '&buftype', 'nofile')
call setbufvar(bid, 'noswapfile', 1)
else
let bid = nvim_create_buf(v:false, v:true)
call setbufvar(bid, '&buftype', 'nofile')
call setbufvar(bid, '&bufhidden', 'hide')
call setbufvar(bid, 'noswapfile', 1)
endif
endif
call setbufvar(bid, '&modifiable', 1)
call deletebufline(bid, 1, '$')
call setbufvar(bid, '&modified', 0)
call setbufvar(bid, '&filetype', '')
return bid
endfunc
"----------------------------------------------------------------------
" free a buffer
"----------------------------------------------------------------------
function! quickui#core#buffer_free(bid)
if !exists('s:buffer_array')
let s:buffer_array = {}
endif
let index = len(s:buffer_array)
let s:buffer_array[index] = a:bid
call setbufvar(a:bid, '&modifiable', 1)
call deletebufline(a:bid, 1, '$')
call setbufvar(a:bid, '&modified', 0)
endfunc
"----------------------------------------------------------------------
" update content
"----------------------------------------------------------------------
function! quickui#core#buffer_update(bid, textlist)
if type(a:textlist) == v:t_list
let textlist = a:textlist
else
let textlist = split('' . a:textlist, '\n', 1)
endif
call setbufvar(a:bid, '&modifiable', 1)
call deletebufline(a:bid, 1, '$')
call setbufline(a:bid, 1, textlist)
call setbufvar(a:bid, '&modified', 0)
endfunc
"----------------------------------------------------------------------
" clear content
"----------------------------------------------------------------------
function! quickui#core#buffer_clear(bid)
call quickui#core#buffer_update(a:bid, [])
endfunc
"----------------------------------------------------------------------
" get a named buffer
"----------------------------------------------------------------------
function! quickui#core#scratch_buffer(name, textlist)
if !exists('s:buffer_cache')
let s:buffer_cache = {}
endif
if a:name != ''
let bid = get(s:buffer_cache, a:name, -1)
else
let bid = -1
endif
if bid < 0
let bid = quickui#core#buffer_alloc()
if a:name != ''
let s:buffer_cache[a:name] = bid
endif
endif
call quickui#core#buffer_update(bid, a:textlist)
call setbufvar(bid, 'current_syntax', '')
return bid
endfunc
"----------------------------------------------------------------------
" dummy filter
"----------------------------------------------------------------------
function! quickui#core#mock_function(id, text)
return 0
endfunc
"----------------------------------------------------------------------
" highlight region
"----------------------------------------------------------------------
function! quickui#core#high_region(name, srow, scol, erow, ecol, virtual)
let sep = (a:virtual == 0)? 'c' : 'v'
let cmd = 'syn region ' . a:name . ' '
let cmd .= ' start=/\%' . a:srow . 'l\%' . a:scol . sep . '/'
let cmd .= ' end=/\%' . a:erow . 'l\%' . a:ecol . sep . '/'
return cmd
endfunc
"----------------------------------------------------------------------
" patterns
"----------------------------------------------------------------------
function! quickui#core#border_extract(pattern)
let parts = ['', '', '', '', '', '', '', '', '', '', '']
for idx in range(11)
let parts[idx] = strcharpart(a:pattern, idx, 1)
endfor
return parts
endfunc
function! quickui#core#border_convert(pattern, nvim_format)
if type(a:pattern) == v:t_string
let p = quickui#core#border_extract(a:pattern)
else
let p = a:pattern
endif
if len(p) == 0
return []
endif
if a:nvim_format == 0
let pattern = [ p[1], p[5], p[7], p[3], p[0], p[2], p[8], p[6] ]
else
let pattern = [ p[0], p[1], p[2], p[5], p[8], p[7], p[6], p[3] ]
endif
return pattern
endfunc
let s:border_styles = {}
let s:border_styles[0] = quickui#core#border_extract(' ')
let s:border_styles[1] = quickui#core#border_extract('+-+|-|+-+++')
let s:border_styles[2] = quickui#core#border_extract('┌─┐│─│└─┘├┤')
let s:border_styles[3] = quickui#core#border_extract('╔═╗║─║╚═╝╟╢')
let s:border_styles[4] = quickui#core#border_extract('╭─╮│─│╰─╯├┤')
let s:border_styles[5] = quickui#core#border_extract('/-\|-|\-/++')
let s:border_ascii = quickui#core#border_extract('+-+|-|+-+++')
let s:border_styles['none'] = []
let s:border_styles['single'] = s:border_styles[2]
let s:border_styles['double'] = s:border_styles[3]
let s:border_styles['rounded'] = s:border_styles[4]
let s:border_styles['solid'] = s:border_styles[0]
let s:border_styles['ascii'] = s:border_styles[1]
let s:border_styles['default'] = s:border_styles[1]
function! quickui#core#border_install(name, pattern)
let s:border_styles[a:name] = quickui#core#border_extract(a:pattern)
endfunc
function! quickui#core#border_get(name)
if has_key(s:border_styles, a:name)
return s:border_styles[a:name]
endif
return s:border_ascii
endfunc
function! quickui#core#border_vim(name)
let border = quickui#core#border_get(a:name)
return quickui#core#border_convert(border, 0)
endfunc
function! quickui#core#border_nvim(name)
let border = quickui#core#border_get(a:name)
return quickui#core#border_convert(border, 1)
endfunc
function! quickui#core#border_auto(name)
if g:quickui#core#has_nvim == 0
return quickui#core#border_vim(a:name)
else
return quickui#core#border_nvim(a:name)
endif
endfunc
"----------------------------------------------------------------------
" returns cursor position for screen coordination
"----------------------------------------------------------------------
function! quickui#core#cursor_pos()
let pos = win_screenpos('.')
return [pos[0] + winline() - 1, pos[1] + wincol() - 1]
endfunc
"----------------------------------------------------------------------
" screen boundary check, returns 1 for in screen, 0 for exceeding
"----------------------------------------------------------------------
function! quickui#core#in_screen(line, column, width, height)
let x = a:column - 1
let y = a:line - 1
let w = a:width
let h = a:height
let screenw = &columns
let screenh = &lines
return (x >= 0 && y >= 0 && x + w <= screenw && y + h <= screenh)? 1 : 0
endfunc
"----------------------------------------------------------------------
" window fit screen
"----------------------------------------------------------------------
function! quickui#core#screen_fit(line, column, width, height)
let x = a:column - 1
let y = a:line - 1
let w = a:width
let h = a:height
let screenw = &columns
let screenh = &lines
let x = (x + w > screenw)? screenw - w : x
let y = (y + h > screenh)? screenh - h : y
let x = (x < 0)? 0 : x
let y = (y < 0)? 0 : y
return [y + 1, x + 1]
endfunc
"----------------------------------------------------------------------
" fit screen
"----------------------------------------------------------------------
function! quickui#core#around_cursor(width, height)
let cursor_pos = quickui#core#cursor_pos()
let row = cursor_pos[0] + 1
let col = cursor_pos[1] + 1
if quickui#core#in_screen(row, col, a:width, a:height)
return [row, col]
endif
if col + a:width - 1 > &columns
let col = col - (1 + a:width)
if quickui#core#in_screen(row, col, a:width, a:height)
return [row, col]
endif
endif
if row + a:height - 1 > &lines
let row = row - (1 + a:height)
if quickui#core#in_screen(row, col, a:width, a:height)
return [row, col]
endif
endif
if cursor_pos[0] + a:height + 2 < &lines
let row = cursor_pos[0] + 1
else
let row = cursor_pos[0] - a:height
endif
if cursor_pos[1] + a:width + 2 < &columns
let col = cursor_pos[1] + 1
else
let col = cursor_pos[1] - a:width
endif
return quickui#core#screen_fit(row, col, a:width, a:height)
endfunc
"----------------------------------------------------------------------
" safe input
"----------------------------------------------------------------------
function! quickui#core#input(prompt, text)
call inputsave()
try
let t = input(a:prompt, a:text)
catch /^Vim:Interrupt$/
let t = "\<c-c>"
endtry
call inputrestore()
return t
endfunc
"----------------------------------------------------------------------
" safe change dir
"----------------------------------------------------------------------
function! quickui#core#chdir(path)
if has('nvim')
let cmd = haslocaldir()? 'lcd' : (haslocaldir(-1, 0)? 'tcd' : 'cd')
else
let cmd = haslocaldir()? ((haslocaldir() == 1)? 'lcd' : 'tcd') : 'cd'
endif
silent execute cmd . ' '. fnameescape(a:path)
endfunc
"----------------------------------------------------------------------
" full file name
"----------------------------------------------------------------------
function! quickui#core#fullname(f)
let f = a:f
if f =~ "'."
try
redir => m
silent exe ':marks' f[1]
redir END
let f = split(split(m, '\n')[-1])[-1]
let f = filereadable(f)? f : ''
catch
let f = '%'
endtry
endif
if f == '%'
let f = expand('%')
if &bt == 'terminal' || &bt == 'nofile'
let f = ''
endif
endif
let f = fnamemodify(f, ':p')
if s:windows
let f = substitute(f, "\\", '/', 'g')
endif
if f =~ '\/$'
let f = fnamemodify(f, ':h')
endif
return f
endfunc
"----------------------------------------------------------------------
" returns nearest parent directory contains one of the markers
"----------------------------------------------------------------------
function! quickui#core#find_root(name, markers, strict)
let name = fnamemodify((a:name != '')? a:name : bufname('%'), ':p')
let finding = ''
" iterate all markers
for marker in a:markers
if marker != ''
" search as a file
let x = findfile(marker, name . '/;')
let x = (x == '')? '' : fnamemodify(x, ':p:h')
" search as a directory
let y = finddir(marker, name . '/;')
let y = (y == '')? '' : fnamemodify(y, ':p:h:h')
" which one is the nearest directory ?
let z = (strchars(x) > strchars(y))? x : y
" keep the nearest one in finding
let finding = (strchars(z) > strchars(finding))? z : finding
endif
endfor
if finding == ''
let path = (a:strict == 0)? fnamemodify(name, ':h') : ''
else
let path = fnamemodify(finding, ':p')
endif
if has('win32') || has('win16') || has('win64') || has('win95')
let path = substitute(path, '\/', '\', 'g')
endif
if path =~ '[\/\\]$'
let path = fnamemodify(path, ':h')
endif
return path
endfunc
"----------------------------------------------------------------------
" find project root
"----------------------------------------------------------------------
function! quickui#core#project_root(name, ...)
let markers = ['.project', '.git', '.hg', '.svn', '.root']
if exists('g:quickui_rootmarks')
let markers = g:quickui_rootmarks
elseif exists('g:asyncrun_rootmarks')
let markers = g:asyncrun_rootmarks
endif
let path = quickui#core#fullname(a:name)
let strict = (a:0 > 0)? (a:1) : 0
return quickui#core#find_root(path, markers, strict)
endfunc
"----------------------------------------------------------------------
" expand macros
"----------------------------------------------------------------------
function! quickui#core#expand_macros()
let macros = {}
let macros['VIM_FILEPATH'] = expand("%:p")
let macros['VIM_FILENAME'] = expand("%:t")
let macros['VIM_FILEDIR'] = expand("%:p:h")
let macros['VIM_FILENOEXT'] = expand("%:t:r")
let macros['VIM_PATHNOEXT'] = expand("%:p:r")
let macros['VIM_FILEEXT'] = "." . expand("%:e")
let macros['VIM_FILETYPE'] = (&filetype)
let macros['VIM_CWD'] = getcwd()
let macros['VIM_RELDIR'] = expand("%:h:.")
let macros['VIM_RELNAME'] = expand("%:p:.")
let macros['VIM_CWORD'] = expand("<cword>")
let macros['VIM_CFILE'] = expand("<cfile>")
let macros['VIM_CLINE'] = line('.')
let macros['VIM_VERSION'] = ''.v:version
let macros['VIM_SVRNAME'] = v:servername
let macros['VIM_COLUMNS'] = ''.&columns
let macros['VIM_LINES'] = ''.&lines
let macros['VIM_GUI'] = has('gui_running')? 1 : 0
let macros['VIM_ROOT'] = quickui#core#project_root('%', 0)
let macros['VIM_HOME'] = expand(split(&rtp, ',')[0])
let macros['VIM_PRONAME'] = fnamemodify(macros['VIM_ROOT'], ':t')
let macros['VIM_DIRNAME'] = fnamemodify(macros['VIM_CWD'], ':t')
let macros['<cwd>'] = macros['VIM_CWD']
let macros['<root>'] = macros['VIM_ROOT']
if expand("%:e") == ''
let macros['VIM_FILEEXT'] = ''
endif
return macros
endfunc
"----------------------------------------------------------------------
" write script to a file and return filename
"----------------------------------------------------------------------
function! quickui#core#write_script(command, pause)
let tmpname = fnamemodify(tempname(), ':h') . '\quickui1.cmd'
let command = a:command
if s:windows != 0
let lines = ["@echo off\r"]
let $VIM_COMMAND = a:command
let $VIM_PAUSE = (a:pause)? 'pause' : ''
let lines += ["call %VIM_COMMAND% \r"]
let lines += ["set VIM_EXITCODE=%ERRORLEVEL%\r"]
let lines += ["call %VIM_PAUSE% \r"]
let lines += ["exit %VIM_EXITCODE%\r"]
else
let shell = split(&shell, ' ', 1)[0]
let lines = ['#! ' . shell]
let lines += [command]
if a:pause != 0
if executable('bash')
let pause = 'read -n1 -rsp "press any key to continue ..."'
let lines += ['bash -c ''' . pause . '''']
else
let lines += ['echo "press enter to continue ..."']
let lines += ['sh -c "read _tmp_"']
endif
endif
let tmpname = fnamemodify(tempname(), ':h') . '/quickui1.sh'
endif
call writefile(lines, tmpname)
if s:windows == 0
if exists('*setfperm')
silent! call setfperm(tmpname, 'rwxrwxrws')
endif
endif
return tmpname
endfunc
"----------------------------------------------------------------------
" string replace
"----------------------------------------------------------------------
function! quickui#core#string_replace(text, old, new)
let data = split(a:text, a:old, 1)
return join(data, a:new)
endfunc
"----------------------------------------------------------------------
" string strip
"----------------------------------------------------------------------
function! quickui#core#string_strip(text)
return substitute(a:text, '^\s*\(.\{-}\)[\t\r\n ]*$', '\1', '')
endfunc
"----------------------------------------------------------------------
" extract opts+command
"----------------------------------------------------------------------
function! quickui#core#extract_opts(command)
let cmd = substitute(a:command, '^\s*\(.\{-}\)[\s\r\n]*$', '\1', '')
let opts = {}
while cmd =~# '^-\%(\w\+\)\%([= ]\|$\)'
let opt = matchstr(cmd, '^-\zs\w\+')
if cmd =~ '^-\w\+='
let val = matchstr(cmd, '^-\w\+=\zs\%(\\.\|\S\)*')
else
let val = ''
endif
let opts[opt] = substitute(val, '\\\(\s\)', '\1', 'g')
let cmd = substitute(cmd, '^-\w\+\%(=\%(\\.\|\S\)*\)\=\s*', '', '')
endwhile
let cmd = substitute(cmd, '^\s*\(.\{-}\)\s*$', '\1', '')
let cmd = substitute(cmd, '^@\s*', '', '')
return [cmd, opts]
endfunc
"----------------------------------------------------------------------
" split cmdline to argv
"----------------------------------------------------------------------
function! quickui#core#split_argv(cmdline)
let cmd = quickui#core#string_strip(a:cmdline)
let argv = []
while cmd =~# '^\%(\\.\|\S\)\+'
let arg = matchstr(cmd, '^\%(\\.\|\S\)\+')
let cmd = substitute(cmd, '^\%(\\.\|\S\)\+\s*', '', '')
let val = substitute(arg, '\\\(\s\)', '\1', 'g')
let argv += [val]
endwhile
return argv
endfunc
"----------------------------------------------------------------------
" execute string
"----------------------------------------------------------------------
function! quickui#core#execute_string(text)
let cmd = a:text
if cmd =~ '^[a-zA-Z0-9_#]\+(.*)$'
exec 'call ' . cmd
elseif cmd =~ '^<key>'
let keys = strpart(cmd, 5)
call feedkeys(keys)
elseif cmd =~ '^@'
let keys = strpart(cmd, 1)
call feedkeys(keys)
elseif cmd =~ '^<plug>'
let keys = strpart(cmd, 6)
call feedkeys("\<plug>" . keys)
else
exec cmd
endif
endfunc

View File

@ -0,0 +1,310 @@
"======================================================================
"
" highlight.vim -
"
" Created by skywind on 2021/12/12
" Last Modified: 2021/12/13 18:32
"
"======================================================================
" vim: set ts=4 sw=4 tw=78 noet :
"----------------------------------------------------------------------
" internal
"----------------------------------------------------------------------
let s:has_hlget = exists('*hlget')? 1 : 0
let s:has_hlset = exists('*hlset')? 1 : 0
"----------------------------------------------------------------------
" get highlighting group
"----------------------------------------------------------------------
function! s:sim_hlget(name)
let error = 0
redir => g:quickui_highlight_tmp
try
exec 'silent hi ' . a:name
catch
let error = 1
endtry
redir END
if error != 0
return []
endif
let capture = g:quickui_highlight_tmp
let items = []
for text in split(capture, '\n')
let text = quickui#core#string_strip(text)
if text == ''
continue
endif
let item = {}
let item.name = matchstr(text, '^\w\+')
if item.name == ''
continue
endif
let parts = split(text, ' ')
if empty(parts)
continue
endif
if text =~ ' cleared$'
let item.cleared = v:true
elseif text =~ ' links to \w\+$'
let links = matchstr(text, ' links to \zs\w\+$')
let item.linksto = quickui#core#string_strip(links)
else
for part in parts[1:]
if part =~ '\w\+='
let key = matchstr(part, '^\w\+')
let val = matchstr(part, '^\w\+=\zs\%(\\.\|\S\)*')
if key == 'term' || key == 'cterm' || key == 'gui'
let opts = {}
for element in split(val, ',')
let opts[element] = v:true
endfor
let item[key] = opts
else
let item[key] = val
endif
elseif part == 'cleared'
endif
endfor
endif
let items += [item]
endfor
return items
endfunc
"----------------------------------------------------------------------
" simulate hlset
"----------------------------------------------------------------------
function! s:sim_hlset(items)
let skip = {'name':1, 'id':1, 'linksto':1, 'force':1}
for item in a:items
let name = get(item, 'name', '')
if name == ''
continue
endif
let force = get(item, 'force', v:false)
let cmd = (force == 0)? 'hi ' : 'hi! '
if get(item, 'cleared', v:false) == v:true
exec cmd . 'clear ' . name
else
let part = []
for key in keys(item)
if has_key(skip, key) == 0
let val = item[key]
if type(val) == v:t_dict
let r = join(keys(val), ',')
else
let r = val
endif
let part += [key . '=' . r]
endif
endfor
let text = cmd . ' ' . name . ' ' . join(part, ' ')
exec text
endif
endfor
endfunc
"----------------------------------------------------------------------
" get highlighting info
"----------------------------------------------------------------------
function! quickui#highlight#get(name, ...)
let resolve = (a:0 > 0)? (a:1) : 0
if s:has_hlget
" return hlget(a:name, resolve)
endif
if !resolve
return s:sim_hlget(a:name)
endif
let items = []
for item in s:sim_hlget(a:name)
if has_key(item, 'linksto') == 0
let items += [item]
continue
endif
let info = item
while 1
if has_key(info, 'linksto') == 0
break
endif
let links = info.linksto
let hr = s:sim_hlget(links)
if empty(hr)
break
endif
let info = hr[0]
endwhile
let info.name = item.name
let items += [info]
endfor
return items
endfunc
"----------------------------------------------------------------------
" set highlight group
"----------------------------------------------------------------------
function! quickui#highlight#set(items)
if s:has_hlset
" return hlset(a:items)
endif
call s:sim_hlset(a:items)
endfunc
"----------------------------------------------------------------------
" clear highlight
"----------------------------------------------------------------------
function! quickui#highlight#clear(name)
if s:has_hlset
let info = {'name': a:name, 'cleared': v:true}
call hlset([info])
else
exec 'hi! clear ' . a:name
endif
endfunc
"----------------------------------------------------------------------
" term add feature
"----------------------------------------------------------------------
function! quickui#highlight#term_add(info, what)
let info = a:info
let what = a:what
if has_key(info, 'term')
if type(info.term) == v:t_dict
let info.term[what] = v:true
elseif type(info.term) == v:t_string
let opts = {}
for key in split(info.term, ',')
let opts[key] = v:true
endfor
let opts[what] = v:true
let info.term = opts
endif
else
let info.term = {}
let info.term[what] = v:true
endif
endfunc
"----------------------------------------------------------------------
" cterm add feature
"----------------------------------------------------------------------
function! quickui#highlight#cterm_add(info, what)
let info = a:info
let what = a:what
if has_key(info, 'cterm')
if type(info.cterm) == v:t_dict
let info.cterm[what] = v:true
elseif type(info.cterm) == v:t_string
let opts = {}
for key in split(info.cterm, ',')
let opts[key] = v:true
endfor
let opts[what] = v:true
let info.cterm = opts
endif
else
let info.cterm = {}
let info.cterm[what] = v:true
endif
endfunc
"----------------------------------------------------------------------
" gui add feature
"----------------------------------------------------------------------
function! quickui#highlight#gui_add(info, what)
let info = a:info
let what = a:what
if has_key(info, 'gui')
if type(info.gui) == v:t_dict
let info.gui[what] = v:true
elseif type(info.gui) == v:t_string
let opts = {}
for key in split(info.gui, ',')
let opts[key] = v:true
endfor
let opts[what] = v:true
let info.gui = opts
endif
else
let info.gui = {}
let info.gui[what] = v:true
endif
endfunc
"----------------------------------------------------------------------
" new underline
"----------------------------------------------------------------------
function! quickui#highlight#grant_underline(info)
let info = a:info
call quickui#highlight#term_add(info, 'underline')
call quickui#highlight#cterm_add(info, 'underline')
call quickui#highlight#gui_add(info, 'underline')
return info
endfunc
"----------------------------------------------------------------------
" add colors
"----------------------------------------------------------------------
function! quickui#highlight#grant_color(info, colors)
for key in keys(a:colors)
let a:info[key] = a:colors[key]
endfor
return a:info
endfunc
"----------------------------------------------------------------------
" add underline feature
"----------------------------------------------------------------------
function! quickui#highlight#make_underline(newname, name)
let hr = quickui#highlight#get(a:name, 1)
if len(hr) == 0
return -1
endif
let info = (len(hr) == 0)? {} : hr[0]
call quickui#highlight#term_add(info, 'underline')
call quickui#highlight#cterm_add(info, 'underline')
call quickui#highlight#gui_add(info, 'underline')
if has_key(info, 'id')
unlet info['id']
endif
let info.name = a:newname
let info.force = v:true
call quickui#highlight#set([info])
return info
endfunc
"----------------------------------------------------------------------
" combine foreground and background colors
"----------------------------------------------------------------------
function! quickui#highlight#overlay(newname, background, foreground)
let hr1 = quickui#highlight#get(a:background, 1)
let hr2 = quickui#highlight#get(a:foreground, 1)
let info1 = empty(hr1)? {} : hr1[0]
let info2 = empty(hr2)? {} : hr2[0]
for key in ['ctermfg', 'guifg']
if has_key(info2, key)
let info1[key] = info2[key]
endif
endfor
let info1.name = a:newname
let info1.force = v:true
call quickui#highlight#set([info1])
endfunc

View File

@ -0,0 +1,375 @@
"======================================================================
"
" input.vim -
"
" Created by skywind on 2021/11/27
" Last Modified: 2021/11/30 01:50
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" internal variables
"----------------------------------------------------------------------
let s:has_nvim = g:quickui#core#has_nvim
let s:history = {}
"----------------------------------------------------------------------
" init
"----------------------------------------------------------------------
function! s:init_input_box(prompt, opts)
let border = get(a:opts, 'border', g:quickui#style#border)
let hwnd = {}
let head = []
if type(a:prompt) == v:t_list
let head = deepcopy(a:prompt)
else
let head = split('' . a:prompt, "\n")
endif
let hwnd.h = 2 + len(head)
let hwnd.lnum = 2 + len(head)
if has_key(a:opts, 'w')
let hwnd.w = a:opts.w
else
let limit = 8
for text in head
let width = strdisplaywidth(text)
let limit = (limit < width)? width : limit
endfor
if &columns >= 80
let limit = (limit < 50)? 50 : limit
endif
let hwnd.w = limit
endif
let hwnd.image = head + [' ', repeat(' ', hwnd.w)]
let hwnd.bid = quickui#core#scratch_buffer('input', hwnd.image)
let hwnd.opts = deepcopy(a:opts)
let hwnd.opts.color = get(a:opts, 'color', 'QuickBG')
let hwnd.opts.bordercolor = get(a:opts, 'bordercolor', 'QuickBorder')
let hwnd.opts.text = get(a:opts, 'text', '')
let hwnd.border = border
let title = ' Input '
let hwnd.rl = quickui#readline#new()
if hwnd.opts.text != ''
call hwnd.rl.set(hwnd.opts.text)
call hwnd.rl.seek(0, 2)
let hwnd.rl.select = 0
endif
let hwnd.pos = 0
let hwnd.wait = get(a:opts, 'wait', 0)
let hwnd.exit = 0
let hwnd.strict = get(a:opts, 'strict', 1)
let hwnd.history = get(hwnd.opts, 'history', '')
if hwnd.history != ''
let key = hwnd.history
let hwnd.rl.history = [''] + get(s:history, key, [])
" echom hwnd.rl.history
endif
if has_key(hwnd.opts, 'row') && has_key(hwnd.opts, 'col')
" pass
else
let ww = hwnd.w
let hh = hwnd.h
let hwnd.opts.col = (&columns - ww) / 2
let hwnd.opts.row = (&lines - hh) / 2
let limit1 = (&lines - 2) * 82 / 100
let limit2 = (&lines - 2)
if hh + 8 < limit1
let hwnd.opts.row = (limit1 - hh) / 2
else
let hwnd.opts.row = (limit2 - hh) / 2
endif
endif
return hwnd
endfunc
"----------------------------------------------------------------------
" create input box object
"----------------------------------------------------------------------
function! s:vim_create_input(prompt, opts)
let hwnd = s:init_input_box(a:prompt, a:opts)
let opts = {'hidden':1, 'wrap':1}
let opts.minwidth = hwnd.w
let opts.maxwidth = hwnd.w
let opts.minheight = hwnd.h
let opts.minheight = hwnd.h
let winid = popup_create(hwnd.bid, opts)
if has_key(a:opts, 'line') == 0 || has_key(a:opts, 'col') == 0
call quickui#utils#center(winid, 1)
endif
let opts = {'mapping':0, 'cursorline':0, 'drag':1}
let opts.border = [0,0,0,0,0,0,0,0,0]
if hwnd.border > 0
let opts.borderchars = quickui#core#border_vim(hwnd.border)
let opts.border = [1,1,1,1,1,1,1,1,1]
let opts.close = 'button'
endif
let opts.padding = [1,1,1,1]
if has_key(a:opts, 'title') && (a:opts.title != '')
let opts.title = ' ' . a:opts.title . ' '
endif
let bc = hwnd.opts.bordercolor
let opts.resize = 0
let opts.highlight = hwnd.opts.color
let opts.borderhighlight = [bc, bc, bc, bc]
let opts.callback = function('s:popup_exit')
let hwnd.winid = winid
let local = quickui#core#popup_local(winid)
let local.hwnd = hwnd
call popup_setoptions(winid, opts)
call popup_show(winid)
redraw
return hwnd
endfunc
"----------------------------------------------------------------------
" exit callback
"----------------------------------------------------------------------
function! s:popup_exit(winid, code)
let local = quickui#core#popup_local(a:winid)
let local.hwnd.exit = 1
endfunc
"----------------------------------------------------------------------
" neovim: create input
"----------------------------------------------------------------------
function! s:nvim_create_input(prompt, opts)
let hwnd = s:init_input_box(a:prompt, a:opts)
let opts = {'focusable':1, 'style':'minimal', 'relative':'editor'}
let title = ' Input '
let border = hwnd.border
let back = quickui#utils#make_border(hwnd.w + 2, hwnd.h + 2, border, title, 1)
let hwnd.back = back
let opts.width = hwnd.w
let opts.height = hwnd.h
let opts.row = hwnd.opts.row
let opts.col = hwnd.opts.col
if has('nvim-0.6.0')
let opts.noautocmd = 1
endif
let winid = nvim_open_win(hwnd.bid, 0, opts)
let hwnd.winid = winid
let background = -1
if border > 0 && get(g:, 'quickui_nvim_simulate_border', 1) != 0
let nbid = quickui#core#scratch_buffer('inputborder', back)
let op = {'relative':'editor', 'focusable':1, 'style':'minimal'}
let op.width = hwnd.w + 4
let op.height = hwnd.h + 4
let op.row = hwnd.opts.row - 2
let op.col = hwnd.opts.col - 2
let bordercolor = hwnd.opts.bordercolor
if has('nvim-0.6.0')
let op.noautocmd = 1
endif
let background = nvim_open_win(nbid, 0, op)
call nvim_win_set_option(background, 'winhl', 'Normal:' . bordercolor)
endif
let hwnd.background = background
call nvim_win_set_option(winid, 'winhl', 'Normal:' . hwnd.opts.color)
return hwnd
endfunc
"----------------------------------------------------------------------
" redraw input area
"----------------------------------------------------------------------
function! s:update_input(hwnd)
let hwnd = a:hwnd
let rl = hwnd.rl
let size = hwnd.w
let ts = float2nr(reltimefloat(reltime()) * 1000)
let blink = rl.blink(ts)
let blink = (hwnd.wait)? 0 : blink
let hwnd.pos = rl.slide(hwnd.pos, size)
let display = rl.render(hwnd.pos, size)
let cmdlist = ['syn clear']
let x = 1
let y = hwnd.lnum
let content = []
for [attr, text] in display
let len = strwidth(text)
let content += [text]
let color = 'QuickInput'
if attr == 1
let color = (blink == 0)? 'QuickCursor' : 'QuickInput'
elseif attr == 2
let color = 'QuickVisual'
elseif attr == 3
let color = (blink == 0)? 'QuickCursor' : 'QuickVisual'
endif
let cmd = quickui#core#high_region(color, y, x, y, x + len, 1)
let cmdlist += [cmd]
let x += len
endfor
let text = join(content, '')
call setbufline(hwnd.bid, y, text)
call setbufvar(hwnd.bid, '&modified', 0)
call quickui#core#win_execute(hwnd.winid, cmdlist)
noautocmd redraw
if 0
echon 'blink='. blink
echon ' <'
call rl.echo(blink, 0, hwnd.w)
echon '>'
endif
endfunc
"----------------------------------------------------------------------
" select all text
"----------------------------------------------------------------------
function! s:select_all(hwnd)
let hwnd = a:hwnd
let rl = hwnd.rl
let hwnd.pos = 0
call rl.seek(0, 2)
if rl.size > 0
let rl.select = 0
endif
let hwnd.pos = rl.slide(hwnd.pos, hwnd.w)
endfunc
"----------------------------------------------------------------------
" create input box
"----------------------------------------------------------------------
function! quickui#input#create(prompt, opts)
if s:has_nvim == 0
let hwnd = s:vim_create_input(a:prompt, a:opts)
else
let hwnd = s:nvim_create_input(a:prompt, a:opts)
endif
let rl = hwnd.rl
let accept = 0
let result = ''
silent! exec 'nohl'
while hwnd.exit == 0
call s:update_input(hwnd)
try
if hwnd.wait != 0
let code = getchar()
else
let code = getchar(0)
endif
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
if type(code) == v:t_number && code == 0
try
exec 'sleep 15m'
continue
catch /^Vim:Interrupt$/
let code = "\<c-c>"
endtry
endif
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<ESC>" || ch == "\<c-c>"
break
endif
if ch == ""
continue
elseif ch == "\<ESC>"
break
elseif ch == "\<cr>"
let result = rl.update()
if result != '' || hwnd.strict == 0
let accept = 1
call rl.history_save()
break
endif
elseif ch == "\<LeftMouse>"
if v:mouse_winid == hwnd.winid
if v:mouse_lnum == hwnd.lnum
let x = v:mouse_col - (s:has_nvim? 1 : 3)
if x >= 0 && x < hwnd.w
let pos = rl.mouse_click(hwnd.pos, x)
call rl.seek(pos, 0)
let rl.select = -1
endif
endif
elseif s:has_nvim != 0
if v:mouse_winid == hwnd.background
if v:mouse_lnum == 1
if v:mouse_col == hwnd.w + 4
break
endif
endif
endif
endif
elseif ch == "\<Up>" || ch == "\<c-p>"
if len(rl.history) > 0
call rl.feed("\<up>")
call s:select_all(hwnd)
endif
elseif ch == "\<Down>" || ch == "\<c-n>"
if len(rl.history) > 0
call rl.feed("\<down>")
call s:select_all(hwnd)
endif
elseif ch == "\<c-d>"
redraw
echon "winsize: " . hwnd.w
elseif ch == "\<c-g>"
call s:select_all(hwnd)
elseif ch == "\<c-r>"
let rop = {}
let text = quickui#utils#read_eval(rop)
let text = split(text, "\n", 1)[0]
let text = substitute(text, '[\r\n\t]', ' ', 'g')
if text != ''
if rl.select >= 0
call rl.visual_delete()
endif
call rl.insert(text)
endif
else
call rl.feed(ch)
endif
endwhile
if s:has_nvim == 0
call popup_close(hwnd.winid)
else
call nvim_win_close(hwnd.winid, 0)
if hwnd.background >= 0
call nvim_win_close(hwnd.background, 0)
endif
endif
call quickui#core#popup_clear(hwnd.winid)
redraw
if hwnd.history != ''
let s:history[hwnd.history] = deepcopy(rl.history)
endif
return result
endfunc
"----------------------------------------------------------------------
" open input box
"----------------------------------------------------------------------
function! quickui#input#open(prompt, ...)
let opts = {'title':'Input'}
let opts.text = (a:0 >= 1)? (a:1) : ''
if (a:0 >= 2)
let opts.history = a:2
endif
let opts.wait = get(g:, 'quickui_input_wait', 0)
return quickui#input#create(a:prompt, opts)
endfunc
"----------------------------------------------------------------------
" testing suit
"----------------------------------------------------------------------
if 0
let opts = {}
let opts.title = 'Input'
" let opts.w = 50
echo quickui#input#open("Enter your name:", 'haha', 'abc')
endif

View File

@ -0,0 +1,664 @@
"======================================================================
"
" listbox.vim -
"
" Created by skywind on 2019/12/20
" Last Modified: 2023/08/30 14:47
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" stats
"----------------------------------------------------------------------
" last position
let g:quickui#listbox#cursor = -1
"----------------------------------------------------------------------
" parse
"----------------------------------------------------------------------
function! quickui#listbox#parse(textlist)
let items = {'image': [], 'column':0, 'nrows':0, 'keys':[], 'cmds':[]}
let items.keymap = {}
let items.displaywidth = 0
let sizes = []
let objects = []
let spliter = ' '
for description in a:textlist
let obj = quickui#core#single_parse(description)
let objects += [obj]
if obj.key_pos >= 0
let items.keymap[tolower(obj.key_char)] = items.nrows
endif
let items.nrows += 1
while len(sizes) < obj.size
let sizes += [0]
endwhile
let items.column = len(sizes)
let index = 0
for part in obj.part
let size = strdisplaywidth(obj.part[index])
if size > sizes[index]
let sizes[index] = size
endif
let index += 1
endfor
endfor
for obj in objects
let start = 1
let index = 0
let output = ' '
let ni = ['', -1]
for part in obj.part
let size = strdisplaywidth(part)
let need = sizes[index]
if size >= need
let element = part
else
let element = part . repeat(' ', need - size)
endif
if obj.key_idx == index
let ni[0] = obj.key_char
let ni[1] = start + obj.key_pos
endif
let output .= element
if index + 1 < len(obj.part)
let output .= spliter
endif
let start += strchars(element) + strchars(spliter)
let index += 1
endfor
let items.image += [output . ' ']
let items.keys += [ni]
let items.cmds += [obj.cmd]
let size = strdisplaywidth(output) + 1
if size > items.displaywidth
let items.displaywidth = size
endif
endfor
return items
endfunc
"----------------------------------------------------------------------
" reposition text offset
"----------------------------------------------------------------------
function! quickui#listbox#reposition()
exec 'normal! zz'
let height = winheight(0)
let size = line('$')
let curline = line('.')
let winline = winline()
let topline = curline - winline + 1
let botline = topline + height - 1
let disline = botline - size
if disline > 0
exec 'normal ggG'
exec ':' . curline
exec 'normal G'
exec ':' . curline
endif
endfunc
"----------------------------------------------------------------------
" highlight keys
"----------------------------------------------------------------------
function! s:highlight_keys(winid, items)
let items = a:items
let index = 0
let cmdlist = []
while index < items.nrows
let key = items.keys[index]
if key[1] >= 0
let px = key[1] + 1
let py = index + 1
let cmd = quickui#core#high_region('QuickKey', py, px, py, px + 1, 1)
let cmdlist += [cmd]
endif
let index += 1
endwhile
call quickui#core#win_execute(a:winid, cmdlist)
endfunc
"----------------------------------------------------------------------
" init window
"----------------------------------------------------------------------
function! s:vim_create_listbox(textlist, opts)
let hwnd = {}
let opts = {}
let items = quickui#listbox#parse(a:textlist)
let winid = popup_create(items.image, {'hidden':1, 'wrap':0})
let bufnr = winbufnr(winid)
let hwnd.winid = winid
let hwnd.items = items
let hwnd.bufnr = bufnr
let hwnd.keymap = quickui#utils#keymap()
let hwnd.hotkey = items.keymap
let hwnd.opts = deepcopy(a:opts)
let hwnd.context = has_key(a:opts, 'context')? a:opts.context : {}
let border = get(a:opts, 'border', g:quickui#style#border)
let w = has_key(a:opts, 'w')? a:opts.w : items.displaywidth
let h = has_key(a:opts, 'h')? a:opts.h : items.nrows
if h + 6 > &lines
let h = &lines - 6
let h = (h < 1)? 1 : h
endif
if w + 4 > &columns
let w = &columns - 4
let w = (w < 1)? 1 : w
endif
let opts = {"minwidth":w, "minheight":h, "maxwidth":w, "maxheight":h}
let ww = w + ((border != 0)? 2 : 0)
let hh = h + ((border != 0)? 2 : 0)
if has_key(a:opts, 'line')
let opts.line = a:opts.line
else
let limit1 = (&lines - 2) * 90 / 100
let limit2 = (&lines - 2)
if h + 4 < limit1
let opts.line = (limit1 - hh) / 2
else
let opts.line = (limit2 - hh) / 2
endif
let opts.line = (opts.line < 1)? 1 : opts.line
endif
if has_key(a:opts, 'col')
let opts.col = a:opts.col
else
let opts.col = (&columns - ww) / 2
let opts.col = (opts.col < 1)? 1 : opts.col
endif
call popup_move(winid, opts)
call setwinvar(winid, '&wincolor', get(a:opts, 'color', 'QuickBG'))
if get(a:opts, 'index', 0) >= 0
let moveto = get(a:opts, 'index', 0) + 1
call popup_show(winid)
call win_execute(winid, 'normal! G')
call win_execute(winid, ':' . moveto)
call win_execute(winid, 'normal! G')
call win_execute(winid, ':' . moveto)
call win_execute(winid, 'call quickui#listbox#reposition()')
endif
let opts = {'cursorline':1, 'drag':1, 'mapping':0}
if get(a:opts, 'manual', 0) == 0
let opts.filter = function('s:popup_filter')
let opts.callback = function('s:popup_exit')
endif
let opts.border = [0,0,0,0,0,0,0,0,0]
if border > 0
let opts.borderchars = quickui#core#border_vim(border)
let opts.border = [1,1,1,1,1,1,1,1,1]
endif
if has_key(a:opts, 'title') && (a:opts.title != '')
let opts.title = ' ' . a:opts.title . ' '
endif
let opts.padding = [0,1,0,1]
if has_key(a:opts, 'close') && (a:opts.close != '')
let opts.close = a:opts.close
endif
let local = quickui#core#popup_local(winid)
let local.hwnd = hwnd
let local.winid = winid
let keymap = hwnd.keymap
if !has_key(a:opts, 'horizon')
let keymap["\<LEFT>"] = 'HALFUP'
let keymap["\<RIGHT>"] = 'HALFDOWN'
let keymap["h"] = 'HALFUP'
let keymap["l"] = 'HALFDOWN'
endif
if has_key(a:opts, 'keymap')
for key in keys(a:opts.keymap)
let keymap[key] = a:opts.keymap[key]
endfor
endif
let hwnd.state = 1
let hwnd.code = 0
let hwnd.tag = ''
let bc = get(a:opts, 'bordercolor', 'QuickBorder')
let opts.borderhighlight = [bc, bc, bc, bc]
call popup_setoptions(winid, opts)
call win_execute(winid, 'syn clear')
if has_key(a:opts, 'syntax')
call win_execute(winid, 'set ft=' . fnameescape(a:opts.syntax))
endif
" call s:highlight_keys(winid, items)
call s:highlight_keys(winid, items)
call popup_show(winid)
return hwnd
endfunc
"----------------------------------------------------------------------
" close list box
"----------------------------------------------------------------------
function! quickui#listbox#close(hwnd)
if a:hwnd.winid > 0
call popup_close(a:hwnd.winid)
call quickui#core#popup_clear(a:hwnd.winid)
let a:hwnd.winid = -1
endif
endfunc
"----------------------------------------------------------------------
" handle exit code
"----------------------------------------------------------------------
function! s:popup_exit(winid, code)
let local = quickui#core#popup_local(a:winid)
let hwnd = local.hwnd
let code = a:code
if a:code > 0
call win_execute(a:winid, ':' . a:code)
redraw
let code = a:code - 1
endif
let hwnd.state = 0
let hwnd.code = code
let g:quickui#listbox#cursor = quickui#utils#get_cursor(a:winid) - 1
call quickui#core#popup_clear(a:winid)
silent! call popup_hide(a:winid)
let g:quickui#listbox#current = hwnd
if has_key(hwnd.opts, 'callback')
call call(hwnd.opts.callback, [code])
endif
if code >= 0 && code < hwnd.items.nrows
let cmd = hwnd.items.cmds[code]
if cmd != ''
redraw
try
exec cmd
catch /.*/
echohl Error
echom v:exception
echohl None
endtry
endif
endif
endfunc
"----------------------------------------------------------------------
" key processing
"----------------------------------------------------------------------
function! s:popup_filter(winid, key)
let local = quickui#core#popup_local(a:winid)
let hwnd = local.hwnd
let keymap = hwnd.keymap
if a:key == "\<ESC>" || a:key == "\<c-c>"
call popup_close(a:winid, -1)
return 1
elseif a:key == "\<CR>" || a:key == "\<SPACE>"
return popup_filter_menu(a:winid, "\<CR>")
elseif a:key == "\<LeftMouse>"
let pos = getmousepos()
if pos.winid == a:winid
if pos.line > 0
call win_execute(a:winid, ':' . pos.line)
call popup_setoptions(a:winid, {})
redraw
return popup_filter_menu(a:winid, "\<CR>")
endif
endif
elseif a:key == ':' || a:key == '/' || a:key == '?'
call quickui#utils#search_or_jump(a:winid, a:key)
return 1
elseif has_key(hwnd.hotkey, a:key)
let index = hwnd.hotkey[a:key]
call popup_close(a:winid, index + 1)
return 1
elseif has_key(keymap, a:key)
let key = keymap[a:key]
if strpart(key, 0, 4) == 'TAG:'
let hwnd.tag = strpart(key, 4)
return popup_filter_menu(a:winid, "\<CR>")
elseif key == 'ESC'
call popup_close(a:winid, -1)
return 1
elseif key == 'NEXT' || key == 'PREV'
call quickui#utils#search_next(a:winid, key)
else
let cmd = 'quickui#listbox#cursor_movement("' . key . '")'
call win_execute(a:winid, 'call ' . cmd)
return 1
endif
endif
return popup_filter_menu(a:winid, a:key)
endfunc
"----------------------------------------------------------------------
" how to move cursor
"----------------------------------------------------------------------
function! quickui#listbox#cursor_movement(where)
let curline = line('.')
let endline = line('$')
let height = winheight('.')
if a:where == 'TOP'
let curline = 0
elseif a:where == 'BOTTOM'
let curline = line('$')
elseif a:where == 'UP'
let curline = curline - 1
elseif a:where == 'DOWN'
let curline = curline + 1
elseif a:where == 'PAGEUP'
let curline = curline - height
elseif a:where == 'PAGEDOWN'
let curline = curline + height
elseif a:where == 'HALFUP'
let curline = curline - height / 2
elseif a:where == 'HALFDOWN'
let curline = curline + height / 2
elseif a:where == 'KEEP'
endif
if curline < 1
let curline = 1
elseif curline > endline
let curline = endline
endif
noautocmd exec ":" . curline
noautocmd exec "normal! 0"
endfunc
"----------------------------------------------------------------------
" block and return result
"----------------------------------------------------------------------
function! quickui#listbox#inputlist(textlist, opts)
if g:quickui#core#has_nvim != 0
let opts = deepcopy(a:opts)
if has_key(opts, 'callback')
unlet opts['callback']
endif
return s:nvim_create_listbox(a:textlist, opts)
endif
let opts = deepcopy(a:opts)
let opts.manual = 1
if has_key(opts, 'callback')
call remove(opts, 'callback')
endif
if len(a:textlist) == 0
return -1000
endif
let hwnd = s:vim_create_listbox(a:textlist, opts)
let winid = hwnd.winid
let hr = -1
" call win_execute(winid, 'normal zz')
call popup_show(winid)
while 1
redraw
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<ESC>" || ch == "\<c-c>"
break
elseif ch == " " || ch == "\<cr>"
let cmd = 'let g:quickui#listbox#index = line(".")'
call win_execute(winid, cmd)
let hr = g:quickui#listbox#index - 1
break
elseif ch == "\<LeftMouse>"
let pos = getmousepos()
if pos.winid == winid
if pos.line > 0
call win_execute(winid, ':' . pos.line)
call popup_setoptions(winid, {})
redraw
let hr = pos.line - 1
break
endif
endif
elseif ch == ':' || ch == '/' || ch == '?'
call quickui#utils#search_or_jump(winid, ch)
call popup_hide(winid)
call popup_show(winid)
elseif has_key(hwnd.hotkey, ch)
let hr = hwnd.hotkey[ch]
if hr >= 0
break
endif
elseif has_key(hwnd.keymap, ch)
let key = hwnd.keymap[ch]
if key == 'ESC'
break
elseif key == 'NEXT' || key == 'PREV'
call quickui#utils#search_next(winid, key)
call popup_hide(winid)
call popup_show(winid)
else
let cmd = 'quickui#listbox#cursor_movement("' . key . '")'
call win_execute(winid, 'call ' . cmd)
call popup_hide(winid)
call popup_show(winid)
endif
endif
endwhile
" echo 'size: '. winheight(winid)
if hr > 0
call quickui#core#win_execute(winid, ':' . (hr + 1))
redraw
endif
let g:quickui#listbox#cursor = quickui#utils#get_cursor(winid) - 1
call quickui#listbox#close(hwnd)
return hr
endfunc
"----------------------------------------------------------------------
" create list box in neovim
"----------------------------------------------------------------------
function! s:nvim_create_listbox(textlist, opts)
let hwnd = {}
let opts = {}
let items = quickui#listbox#parse(a:textlist)
let bid = quickui#core#scratch_buffer('listbox', items.image)
let hwnd.items = items
let hwnd.bid = bid
let hwnd.keymap = quickui#utils#keymap()
let hwnd.hotkey = items.keymap
let hwnd.opts = deepcopy(a:opts)
let hwnd.context = has_key(a:opts, 'context')? a:opts.context : {}
let border = get(a:opts, 'border', g:quickui#style#border)
let w = has_key(a:opts, 'w')? a:opts.w : items.displaywidth
let h = has_key(a:opts, 'h')? a:opts.h : items.nrows
if h + 6 > &lines
let h = &lines - 6
let h = (h < 1)? 1 : h
endif
if w + 4 > &columns
let w = &columns - 4
let w = (w < 1)? 1 : w
endif
let ww = w + ((border != 0)? 2 : 0)
let hh = h + ((border != 0)? 2 : 0)
let opts = {'width':w, 'height':h, 'focusable':1, 'style':'minimal'}
let opts.relative = 'editor'
if has_key(a:opts, 'line')
let opts.row = a:opts.line - 1
else
let limit1 = (&lines - 2) * 90 / 100
let limit2 = (&lines - 2)
" echom printf("limit1=%d limit2=%d h=%d hh=%d", limit1, limit2, h, hh)
if h + 4 < limit1
let opts.row = (limit1 - hh) / 2
else
let opts.row = (limit2 - hh) / 2
endif
let opts.row = (opts.row < 0)? 0 : opts.row
endif
if has_key(a:opts, 'col')
let opts.col = a:opts.col - 1
else
let opts.col = (&columns - ww) / 2 - 1
let opts.col = (opts.col < 0)? 0 : opts.col
endif
let border = get(a:opts, 'border', g:quickui#style#border)
let background = -1
let hwnd.opts.color = get(a:opts, 'color', 'QuickBG')
let color = hwnd.opts.color
if border > 0 && get(g:, 'quickui_nvim_simulate_border', 1) != 0
let opts.row += 1
let opts.col += 1
endif
if has('nvim-0.6.0')
let opts.noautocmd = 1
endif
let winid = nvim_open_win(bid, 0, opts)
let button = (get(a:opts, 'close', '') == 'button')? 1 : 0
if border > 0 && get(g:, 'quickui_nvim_simulate_border', 1) != 0
let title = has_key(a:opts, 'title')? ' ' . a:opts.title . ' ' : ''
let back = quickui#utils#make_border(w, h, border, title, button)
let nbid = quickui#core#scratch_buffer('listborder', back)
let op = {'relative':'editor', 'focusable':1, 'style':'minimal'}
let op.width = w + 2
let op.height = h + 2
let op.row = opts.row - 1
let op.col = opts.col - 1
let bordercolor = get(a:opts, 'bordercolor', 'QuickBorder')
if has('nvim-0.6.0')
let op.noautocmd = 1
endif
let background = nvim_open_win(nbid, 0, op)
call nvim_win_set_option(background, 'winhl', 'Normal:'. bordercolor)
endif
let hwnd.winid = winid
call nvim_win_set_option(winid, 'winhl', 'Normal:'. color)
if get(a:opts, 'index', 0) >= 0
let moveto = get(a:opts, 'index', 0) + 1
call quickui#core#win_execute(winid, 'noautocmd normal! ggG')
call quickui#core#win_execute(winid, 'noautocmd :' . moveto)
call quickui#core#win_execute(winid, 'noautocmd normal! 0')
endif
let border = get(a:opts, 'border', 1)
let keymap = hwnd.keymap
if !has_key(a:opts, 'horizon')
let keymap["\<LEFT>"] = 'HALFUP'
let keymap["\<RIGHT>"] = 'HALFDOWN'
let keymap["h"] = 'HALFUP'
let keymap["l"] = 'HALFDOWN'
endif
if has_key(a:opts, 'keymap')
for key in keys(a:opts.keymap)
let keymap[key] = a:opts.keymap[key]
endfor
endif
let hwnd.state = 1
let hwnd.code = 0
let hwnd.tag = ''
call quickui#core#win_execute(winid, 'setlocal nowrap')
call quickui#core#win_execute(winid, 'syn clear')
if has_key(a:opts, 'syntax')
let syntax = fnameescape(a:opts.syntax)
call quickui#core#win_execute(winid, 'set ft=' . syntax)
endif
call s:highlight_keys(winid, items)
call quickui#core#win_execute(winid, "setlocal cursorline scrolloff=0")
if exists('+cursorlineopt')
call quickui#core#win_execute(winid, "setlocal cursorlineopt=both")
endif
let retval = -1
while 1
noautocmd redraw!
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<ESC>" || ch == "\<c-c>"
break
elseif ch == "\<cr>" || ch == "\<space>"
let retval = quickui#utils#get_cursor(winid) - 1
break
elseif ch == "\<LeftMouse>"
if v:mouse_winid == winid
if v:mouse_lnum > 0
let cmd = ':' . v:mouse_lnum
call quickui#core#win_execute(winid, cmd)
redraw!
sleep 10m
let retval = v:mouse_lnum - 1
break
endif
elseif v:mouse_winid == background
if button != 0 && v:mouse_lnum == 1
if v:mouse_col == w + 2
break
endif
endif
endif
elseif ch == ':' || ch == '/' || ch == '?'
call quickui#utils#search_or_jump(winid, ch)
let cmd = 'call quickui#listbox#cursor_movement("KEEP")'
noautocmd call quickui#core#win_execute(winid, cmd)
elseif has_key(hwnd.hotkey, ch)
let retval = hwnd.hotkey[ch]
break
elseif has_key(keymap, ch)
let key = keymap[ch]
if strpart(key, 0, 4) == 'TAG:'
let hwnd.tag = strpart(key, 4)
let retval = quickui#utils#get_cursor(winid) - 1
break
elseif key == "ESC"
break
elseif key == 'NEXT' || key == 'PREV'
call quickui#utils#search_next(winid, key)
else
let cmd = 'quickui#listbox#cursor_movement("' . key . '")'
noautocmd call quickui#core#win_execute(winid, 'call ' . cmd)
endif
endif
endwhile
let hwnd.code = retval
if retval > 0
call quickui#core#win_execute(winid, ':' . (retval + 1))
endif
let g:quickui#listbox#cursor = quickui#utils#get_cursor(winid) - 1
call nvim_win_close(winid, 0)
if background >= 0
call nvim_win_close(background, 0)
endif
redraw!
let hwnd.state = 0
let g:quickui#listbox#current = hwnd
if has_key(hwnd.opts, 'callback')
call call(hwnd.opts.callback, [retval])
endif
if retval >= 0 && retval < hwnd.items.nrows
let cmd = hwnd.items.cmds[retval]
if cmd != ''
try
exec cmd
catch /.*/
echohl Error
echom v:exception
echohl None
endtry
endif
endif
return retval
endfunc
"----------------------------------------------------------------------
" open popup and run command when select an item
"----------------------------------------------------------------------
function! quickui#listbox#open(content, opts)
if g:quickui#core#has_nvim == 0
return s:vim_create_listbox(a:content, a:opts)
else
return s:nvim_create_listbox(a:content, a:opts)
endif
endfunc

View File

@ -0,0 +1,828 @@
"======================================================================
"
" menu.vim - main menu bar
"
" Created by skywind on 2019/12/24
" Last Modified: 2019/12/30 01:14
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" namespace of configuration
"----------------------------------------------------------------------
let s:namespace = { 'system':{'config':{}, 'weight':100, 'index':0} }
let s:name = 'system'
"----------------------------------------------------------------------
" switch config namespace
"----------------------------------------------------------------------
function! quickui#menu#switch(name)
if !has_key(s:namespace, a:name)
let s:namespace[a:name] = {}
let s:namespace[a:name].config = {}
let s:namespace[a:name].index = 0
let s:namespace[a:name].weight = 100
endif
let s:name = a:name
endfunc
"----------------------------------------------------------------------
" clear all entries in current namespace
"----------------------------------------------------------------------
function! quickui#menu#reset()
let current = s:namespace[s:name].config
let s:namespace[s:name].weight = 100
let s:namespace[s:name].index = 0
for key in keys(current)
call remove(current, key)
endfor
endfunc
"----------------------------------------------------------------------
" register entry: (section='File', entry='&Save', command='w')
"----------------------------------------------------------------------
function! quickui#menu#register(section, entry, command, help)
let current = s:namespace[s:name].config
if !has_key(current, a:section)
let index = 0
let maximum = 0
for name in keys(current)
let w = current[name].weight
let maximum = (index == 0)? w : ((maximum < w)? w : maximum)
let index += 1
endfor
let current[a:section] = {'name':a:section, 'weight':0, 'items':[]}
let current[a:section].ft = ''
let current[a:section].weight = s:namespace[s:name].weight
let s:namespace[s:name].weight += 10
endif
let menu = current[a:section]
let item = {'name':a:entry, 'cmd':a:command, 'help':a:help}
let menu.items += [item]
endfunc
"----------------------------------------------------------------------
" remove entry:
"----------------------------------------------------------------------
function! quickui#menu#remove(section, index)
let current = s:namespace[s:name].config
if !has_key(current, a:section)
return -1
endif
let menu = current[a:section]
if type(a:index) == v:t_number
let index = (a:index < 0)? (len(menu.items) + a:index) : a:index
if index < 0 || index >= len(menu.items)
return -1
endif
call remove(menu.items, index)
elseif type(a:index) == v:t_string
if a:index ==# '*'
menu.items = []
else
let index = -1
for ii in range(len(menu.items))
if menu.items[ii].name ==# a:index
let index = ii
break
endif
endfor
if index < 0
return -1
endif
call remove(menu.items, index)
endif
endif
return 0
endfunc
"----------------------------------------------------------------------
" return items key
"----------------------------------------------------------------------
function! quickui#menu#section(section)
let current = s:namespace[s:name].config
return get(current, a:section, v:null)
endfunc
"----------------------------------------------------------------------
" install a how section
"----------------------------------------------------------------------
function! quickui#menu#install(section, content, ...)
let current = s:namespace[s:name].config
if a:0 > 2 && (a:3 != 0)
while 1
if quickui#menu#remove(a:section, 0) != 0
break
endif
endwhile
endif
if type(a:content) == v:t_list
for item in a:content
if type(item) == v:t_dict
call quickui#menu#register(a:section, item.name, item.command)
elseif type(item) == v:t_list
let size = len(item)
let name = (size >= 1)? item[0] : ''
let cmd = (size >= 2)? item[1] : ''
let help = (size >= 3)? item[2] : ''
call quickui#menu#register(a:section, name, cmd, help)
elseif type(item) == v:t_string
call quickui#menu#register(a:section, item, '', '')
endif
endfor
elseif type(a:content) == v:t_dict
for name in keys(a:content)
let cmd = a:content[name]
call quickui#menu#register(a:section, name, cmd, '')
endfor
endif
if a:0 > 0 && has_key(current, a:section)
if type(a:1) == v:t_number
let current[a:section].weight = a:1
endif
endif
if a:0 > 1 && has_key(current, a:section)
let current[a:section].ft = a:2
endif
endfunc
"----------------------------------------------------------------------
" clear all entries in current namespace
"----------------------------------------------------------------------
function! quickui#menu#clear(section)
let current = s:namespace[s:name].config
if has_key(current, a:section)
call remove(current, a:section)
endif
endfunc
"----------------------------------------------------------------------
" change weight
"----------------------------------------------------------------------
function! quickui#menu#change_weight(section, weight)
let current = s:namespace[s:name].config
if has_key(current, a:section)
let current[a:section].weight = a:weight
endif
endfunc
"----------------------------------------------------------------------
" change file types
"----------------------------------------------------------------------
function! quickui#menu#change_ft(section, ft)
let current = s:namespace[s:name].config
if has_key(current, a:section)
let current[a:section].ft = a:ft
endif
endfunc
"----------------------------------------------------------------------
" preset menu
"----------------------------------------------------------------------
function! quickui#menu#preset(section, context, ...)
let current = s:namespace[s:name].config
let save_items = []
if has_key(current, a:section)
let save_items = current[a:section].items
let current[a:section].items = []
endif
if a:0 == 0
call quickui#menu#install(a:section, a:context)
else
call quickui#menu#install(a:section, a:context, a:1)
endif
if len(save_items) > 0
if len(a:context) > 0
call quickui#menu#register(a:section, '--', '', '')
endif
for ni in save_items
call quickui#menu#register(a:section, ni.name, ni.cmd, ni.help)
endfor
endif
endfunc
"----------------------------------------------------------------------
" compare section
"----------------------------------------------------------------------
function! s:section_compare(s1, s2)
if a:s1[0] == a:s2[0]
return 0
else
return (a:s1[0] > a:s2[0])? 1 : -1
endif
endfunc
"----------------------------------------------------------------------
" get section
"----------------------------------------------------------------------
function! quickui#menu#available(name)
let current = s:namespace[a:name].config
let menus = []
let callback = get(g:, 'quickui_menu_filter', '')
let F = (callback != '')? function(callback) : ''
for name in keys(current)
let menu = current[name]
if menu.ft != ''
let fts = split(menu.ft, ',')
if index(fts, &ft) < 0
continue
endif
endif
if callback != ''
if F(menu.name) == 0
continue
endif
endif
if len(menu.items) > 0
let menus += [[menu.weight, menu.name]]
endif
endfor
call sort(menus, 's:section_compare')
let result = []
for obj in menus
let result += [obj[1]]
endfor
return result
endfunc
"----------------------------------------------------------------------
" parse
"----------------------------------------------------------------------
function! s:parse_menu(name, padding)
let current = s:namespace[a:name].config
let inst = {'items':[], 'text':'', 'width':0, 'hotkey':{}}
let start = 0
let split = repeat(' ', a:padding)
let names = quickui#menu#available(a:name)
let index = 0
let size = len(names)
for section in names
let menu = current[section]
let item = {'name':menu.name, 'text':''}
let obj = quickui#core#escape(menu.name)
let item.text = ' ' . obj[0] . ' '
let item.key_char = obj[1]
let item.key_pos = (obj[4] < 0)? -1 : (obj[4] + 1)
let item.x = start
let item.w = strwidth(item.text)
let start += item.w + strwidth(split)
let inst.items += [item]
let inst.text .= item.text . ((index + 1 < size)? split : '')
if item.key_pos >= 0
let key = tolower(item.key_char)
let inst.hotkey[key] = index
endif
let index += 1
endfor
let inst.width = strwidth(inst.text)
return inst
endfunc
"----------------------------------------------------------------------
" internal
"----------------------------------------------------------------------
let s:cmenu = {'state':0, 'index':0, 'size':0, 'winid':-1, 'drop':-1}
"----------------------------------------------------------------------
" create popup ui
"----------------------------------------------------------------------
function! quickui#menu#create(opts)
if s:cmenu.state != 0
return -1
endif
let name = get(a:opts, 'name', s:name)
if !has_key(s:namespace, name)
return -1
endif
let current = s:namespace[name].config
let s:cmenu.inst = s:parse_menu(name, 2)
if s:cmenu.inst.width + 5 >= &columns
let s:cmenu.inst = s:parse_menu(name, 1)
if s:cmenu.inst.width + 5 >= &columns
let s:cmenu.inst = s:parse_menu(name, 0)
endif
endif
let s:cmenu.name = name
let s:cmenu.index = s:namespace[name].index
let s:cmenu.width = &columns
let s:cmenu.size = len(s:cmenu.inst.items)
let s:cmenu.current = current
let winid = popup_create([s:cmenu.inst.text], {'hidden':1, 'wrap':0})
let bufnr = winbufnr(winid)
let s:cmenu.winid = winid
let s:cmenu.bufnr = bufnr
let s:cmenu.cfg = deepcopy(a:opts)
let w = s:cmenu.width
let opts = {"minwidth":w, "maxwidth":w, "minheight":1, "maxheight":1}
let opts.line = 1
let opts.col = 1
call popup_move(winid, opts)
call setwinvar(winid, '&wincolor', get(a:opts, 'color', 'QuickBG'))
let opts = {'mapping':0, 'cursorline':0, 'drag':0, 'zindex':31000}
let opts.border = [0,0,0,0,0,0,0,0,0]
let opts.padding = [0,0,0,0]
let opts.filter = 'quickui#menu#filter'
let opts.callback = 'quickui#menu#callback'
if 1
let keymap = quickui#utils#keymap()
let s:cmenu.keymap = keymap
endif
let s:cmenu.hotkey = s:cmenu.inst.hotkey
" echo "hotkey: ". string(s:cmenu.hotkey)
let s:cmenu.drop = -1
let s:cmenu.state = 1
let s:cmenu.context = -1
call popup_setoptions(winid, opts)
call quickui#menu#update()
call popup_show(winid)
return 0
endfunc
"----------------------------------------------------------------------
" render menu
"----------------------------------------------------------------------
function! quickui#menu#update()
let winid = s:cmenu.winid
if s:cmenu.state == 0
return -1
endif
let inst = s:cmenu.inst
let cmdlist = ['syn clear']
let index = 0
for item in inst.items
if item.key_pos >= 0
let x = item.key_pos + item.x + 1
let cmd = quickui#core#high_region('QuickKey', 1, x, 1, x + 1, 1)
let cmdlist += [cmd]
endif
let index += 1
endfor
let index = s:cmenu.index
if index >= 0 && index < s:cmenu.size
let x = inst.items[index].x + 1
let e = x + inst.items[index].w
let cmd = quickui#core#high_region('QuickSel', 1, x, 1, e, 1)
let cmdlist += [cmd]
endif
call quickui#core#win_execute(winid, cmdlist)
return 0
endfunc
"----------------------------------------------------------------------
" close menu
"----------------------------------------------------------------------
function! quickui#menu#close()
if s:cmenu.state != 0
call popup_close(s:cmenu.winid)
let s:cmenu.winid = -1
let s:cmenu.state = 0
endif
endfunc
"----------------------------------------------------------------------
" exit callback
"----------------------------------------------------------------------
function! quickui#menu#callback(winid, code)
" echom "quickui#menu#callback"
let s:cmenu.state = 0
let s:cmenu.winid = -1
let s:namespace[s:cmenu.name].index = s:cmenu.index
if s:cmenu.context >= 0
call popup_close(s:cmenu.context, -3)
let s:cmenu.context = -1
endif
redraw
echo ""
redraw
endfunc
"----------------------------------------------------------------------
" event handler
"----------------------------------------------------------------------
function! quickui#menu#filter(winid, key)
let keymap = s:cmenu.keymap
if a:key == "\<ESC>" || a:key == "\<c-c>"
call popup_close(a:winid, -1)
return 1
elseif a:key == "\<LeftMouse>"
return s:mouse_click()
elseif has_key(s:cmenu.hotkey, a:key)
let index = s:cmenu.hotkey[a:key]
let index = (index < 0)? (s:cmenu.size - 1) : index
let index = (index >= s:cmenu.size)? 0 : index
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
call quickui#menu#update()
call s:context_dropdown()
redraw
elseif has_key(keymap, a:key)
let key = keymap[a:key]
call s:movement(key)
redraw
return 1
endif
return 1
endfunc
"----------------------------------------------------------------------
" moving
"----------------------------------------------------------------------
function! s:movement(key)
if a:key == 'ESC'
if g:quickui#core#has_nvim == 0
call popup_close(s:cmenu.winid, -1)
endif
return 1
elseif a:key == 'LEFT' || a:key == 'RIGHT'
let index = s:cmenu.index
if index < 0
let index = 0
elseif a:key == 'LEFT'
let index -= 1
elseif a:key == 'RIGHT'
let index += 1
endif
let index = (index < 0)? (s:cmenu.size - 1) : index
let index = (index >= s:cmenu.size)? 0 : index
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
call quickui#menu#update()
" echo "MOVE: " . index
elseif a:key == 'PAGEUP' || a:key == 'PAGEDOWN'
let index = (a:key == 'PAGEUP')? 0 : (s:cmenu.size - 1)
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
call quickui#menu#update()
elseif a:key == 'ENTER' || a:key == 'DOWN'
if g:quickui#core#has_nvim == 0
call s:context_dropdown()
else
return s:neovim_dropdown()
endif
endif
return 0
endfunc
"----------------------------------------------------------------------
" mouse click
"----------------------------------------------------------------------
function! s:mouse_click()
let pos = getmousepos()
if pos.winid != s:cmenu.winid || pos.line != 1
call popup_close(s:cmenu.winid, -1)
return 0
endif
let x = pos.wincol - 1
let index = 0
let select = -1
for item in s:cmenu.inst.items
if x >= item.x && x < item.x + item.w
let select = index
endif
let index += 1
endfor
if select >= 0
let s:cmenu.index = select
if s:cmenu.context >= 0
call popup_close(s:cmenu.index, -1)
let s:cmenu.context = -1
endif
call quickui#menu#update()
call s:context_dropdown()
redraw
endif
return 1
endfunc
"----------------------------------------------------------------------
" drop down context
"----------------------------------------------------------------------
function! s:context_dropdown()
let cursor = s:cmenu.index
if cursor < 0 || cursor >= s:cmenu.size || s:cmenu.state == 0
return 0
endif
if s:cmenu.state == 2
call popup_close(s:cmenu.context, -3)
let s:cmenu.state = 1
let s:cmenu.context = -1
endif
let item = s:cmenu.inst.items[s:cmenu.index]
let opts = {'col': item.x + 1, 'line': 2, 'horizon':1, 'zindex':31100}
let opts.callback = 'quickui#menu#context_exit'
let opts.reserve = 1
let opts.lazyredraw = 1
let cfg = s:cmenu.current[item.name]
let s:cmenu.dropdown = []
for item in cfg.items
let s:cmenu.dropdown += [[item.name, item.cmd, item.help]]
endfor
let index = get(cfg, 'index', 0)
let opts.index = (index < 0 || index >= len(cfg.items))? 0 : index
let cfg.index = opts.index
let hwnd = quickui#context#open(s:cmenu.dropdown, opts)
let s:cmenu.context = hwnd.winid
let s:cmenu.state = 1
endfunc
"----------------------------------------------------------------------
" context menu callback
"----------------------------------------------------------------------
function! quickui#menu#context_exit(code)
" echom "quickui#menu#context_exit"
let s:cmenu.context = -1
let hwnd = g:quickui#context#current
if has_key(hwnd, 'index') && hwnd.index >= 0
let item = s:cmenu.inst.items[s:cmenu.index]
let cfg = s:cmenu.current[item.name]
let cfg.index = hwnd.index
" echo "save index: ".hwnd.index
endif
if a:code >= 0 || a:code == -3
if s:cmenu.state > 0 && s:cmenu.winid >= 0
call popup_close(s:cmenu.winid, 0)
endif
return 0
elseif a:code == -1 " close context menu by ESC
if s:cmenu.state > 0 && s:cmenu.winid >= 0
call popup_close(s:cmenu.winid, 0)
endif
elseif a:code == -2 " close context menu by mouse
if s:cmenu.state > 0 && s:cmenu.winid >= 0
let pos = getmousepos()
if pos.winid != s:cmenu.winid
call popup_close(s:cmenu.winid, 0)
endif
endif
elseif a:code == -1000 || a:code == -2000
call s:movement((a:code == -1000)? 'LEFT' : 'RIGHT')
call s:movement('DOWN')
elseif a:code == -1001 || a:code == -2001
call s:movement((a:code == -1001)? 'PAGEUP' : 'PAGEDOWN')
call s:movement('DOWN')
endif
return 0
endfunc
"----------------------------------------------------------------------
" open menu
"----------------------------------------------------------------------
function! quickui#menu#open(...)
let opts = {}
if a:0 > 0
let opts.name = a:1
endif
if g:quickui#core#has_nvim == 0
call quickui#menu#create(opts)
else
call quickui#menu#nvim_open_menu(opts)
endif
endfunc
"----------------------------------------------------------------------
" neovim dropdown context: returns non-zero for exit
"----------------------------------------------------------------------
function! s:neovim_dropdown()
let cursor = s:cmenu.index
if cursor < 0 || cursor >= s:cmenu.size || s:cmenu.state == 0
return 0
endif
if s:cmenu.state == 2
let s:cmenu.state = 1
let s:cmenu.context = -1
return 1
endif
let item = s:cmenu.inst.items[s:cmenu.index]
let opts = {'col': item.x + 1, 'line': 2, 'horizon':1, 'zindex':31100}
let opts.reserve = 1
let opts.lazyredraw = 1
let cfg = s:cmenu.current[item.name]
let s:cmenu.dropdown = []
for item in cfg.items
let s:cmenu.dropdown += [[item.name, '', item.help]]
endfor
let index = get(cfg, 'index', 0)
let opts.index = (index < 0 || index >= len(cfg.items))? 0 : index
let cfg.index = opts.index
let hr = quickui#context#open(s:cmenu.dropdown, opts)
let cfg.index = g:quickui#context#current.index
let s:cmenu.next = 0
if hr >= 0
if hr < len(cfg.items)
let s:cmenu.script = cfg.items[hr].cmd
endif
return 1
elseif hr == -1000
call s:movement('LEFT')
let s:cmenu.next = 1
elseif hr == -2000
call s:movement('RIGHT')
let s:cmenu.next = 1
elseif hr == -1001
call s:movement('PAGEUP')
let s:cmenu.next = 1
elseif hr == -2001
call s:movement('PAGEDOWN')
let s:cmenu.next = 1
elseif hr == -2
call s:neovim_click()
endif
return (s:cmenu.next == 0)? 1 : 0
endfunc
"----------------------------------------------------------------------
" returns non-zero to quit
"----------------------------------------------------------------------
function! s:neovim_click()
if v:mouse_winid != s:cmenu.winid || v:mouse_lnum != 1
return 1
endif
let x = v:mouse_col - 1
let index = 0
let select = -1
for item in s:cmenu.inst.items
if x >= item.x && x < item.x + item.w
let select = index
endif
let index += 1
endfor
if select >= 0
let s:cmenu.index = select
let s:cmenu.next = 1
endif
return 0
endfunc
"----------------------------------------------------------------------
" neovim open menu
"----------------------------------------------------------------------
function! quickui#menu#nvim_open_menu(opts)
if s:cmenu.state != 0
" return -1
endif
let name = get(a:opts, 'name', s:name)
if !has_key(s:namespace, name)
return -1
endif
let current = s:namespace[name].config
let s:cmenu.inst = s:parse_menu(name, 2)
if s:cmenu.inst.width + 5 >= &columns
let s:cmenu.inst = s:parse_menu(name, 1)
if s:cmenu.inst.width + 5 >= &columns
let s:cmenu.inst = s:parse_menu(name, 0)
endif
endif
let s:cmenu.name = name
let s:cmenu.index = s:namespace[name].index
let s:cmenu.width = &columns
let s:cmenu.size = len(s:cmenu.inst.items)
let s:cmenu.current = current
let bid = quickui#core#scratch_buffer('menu', [s:cmenu.inst.text])
let w = s:cmenu.width
let opts = {'width':w, 'height':1, 'focusable':1, 'style':'minimal'}
let opts.col = 0
let opts.row = 0
let opts.relative = 'editor'
let s:cmenu.bufnr = bid
if has('nvim-0.6.0')
let opts.noautocmd = 1
endif
let winid = nvim_open_win(bid, 0, opts)
let s:cmenu.winid = winid
let s:cmenu.cfg = deepcopy(a:opts)
let w = s:cmenu.width
let color = get(a:opts, 'color', 'QuickBG')
call nvim_win_set_option(winid, 'winhl', 'Normal:'. color)
let s:cmenu.hotkey = s:cmenu.inst.hotkey
let s:cmenu.state = 1
let s:cmenu.context = -1
let s:cmenu.next = 0
let keymap = quickui#utils#keymap()
let s:cmenu.keymap = keymap
let s:cmenu.script = ''
call quickui#menu#update()
while 1
noautocmd call quickui#menu#update()
if s:cmenu.next == 0
noautocmd redraw
elseif s:cmenu.next == 1
let s:cmenu.next = 0
call quickui#menu#update()
if s:neovim_dropdown() != 0
break
else
continue
endif
elseif s:cmenu.next == 2
let s:cmenu.next = 0
continue
endif
let s:cmenu.next = 0
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<ESC>" || ch == "\<c-c>"
break
elseif ch == "\<LeftMouse>"
if s:neovim_click() != 0
break
endif
elseif has_key(s:cmenu.hotkey, ch)
let index = s:cmenu.hotkey[ch]
let index = (index < 0)? (s:cmenu.size - 1) : index
let index = (index >= s:cmenu.size)? 0 : index
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
call quickui#menu#update()
if s:neovim_dropdown() != 0
break
endif
elseif has_key(keymap, ch)
let key = keymap[ch]
if s:movement(key) != 0
break
endif
endif
endwhile
call nvim_win_close(winid, 0)
redraw
echo ""
redraw
let s:namespace[name].index = s:cmenu.index
if s:cmenu.script != ''
let script = s:cmenu.script
exec script
endif
endfunc
"----------------------------------------------------------------------
" testing suit
"----------------------------------------------------------------------
if 0
call quickui#menu#switch('test')
call quickui#menu#reset()
call quickui#menu#install('H&elp', [
\ [ '&Content', 'echo 4' ],
\ [ '&About', 'echo 5' ],
\ ])
call quickui#menu#install('&File', [
\ [ "&New File\tCtrl+n", '' ],
\ [ "&Open File\t(F3)", 'echo 1' ],
\ [ "&Close", 'echo 3' ],
\ [ "--", '' ],
\ [ "&Save\tCtrl+s", ''],
\ [ "Save &As", '' ],
\ [ "Save All", '' ],
\ [ "--", '' ],
\ [ "E&xit\tAlt+x", '' ],
\ ])
call quickui#menu#install('&Edit', [
\ [ '&Copy', 'echo 1', 'help1' ],
\ [ '&Paste', 'echo 2', 'help2' ],
\ [ '&Find', 'echo 3', 'help3' ],
\ ])
call quickui#menu#install('&Tools', [
\ [ '&Copy', 'echo 1', 'help1' ],
\ [ '&Paste', 'echo 2', 'help2' ],
\ [ '&Find', 'echo 3', 'help3' ],
\ ])
call quickui#menu#install('&Window', [])
call quickui#menu#change_weight('H&elp', 1000)
call quickui#menu#switch('system')
call quickui#menu#open('test')
endif

View File

@ -0,0 +1,719 @@
"======================================================================
"
" palette.vim -
"
" Created by skywind on 2021/12/23
" Last Modified: 2022/09/25 01:31
"
"======================================================================
" vim: set ts=4 sw=4 tw=78 noet :
"----------------------------------------------------------------------
" terminal palette of 256 colors
"----------------------------------------------------------------------
let g:quickui#palette#colors = [
\ { 'color': 0, 'name': 'Black', 'hex': '#000000' },
\ { 'color': 1, 'name': 'Maroon', 'hex': '#800000' },
\ { 'color': 2, 'name': 'Green', 'hex': '#008000' },
\ { 'color': 3, 'name': 'Olive', 'hex': '#808000' },
\ { 'color': 4, 'name': 'Navy', 'hex': '#000080' },
\ { 'color': 5, 'name': 'Purple', 'hex': '#800080' },
\ { 'color': 6, 'name': 'Teal', 'hex': '#008080' },
\ { 'color': 7, 'name': 'Silver', 'hex': '#c0c0c0' },
\ { 'color': 8, 'name': 'Grey', 'hex': '#808080' },
\ { 'color': 9, 'name': 'Red', 'hex': '#ff0000' },
\ { 'color': 10, 'name': 'Lime', 'hex': '#00ff00' },
\ { 'color': 11, 'name': 'Yellow', 'hex': '#ffff00' },
\ { 'color': 12, 'name': 'Blue', 'hex': '#0000ff' },
\ { 'color': 13, 'name': 'Fuchsia', 'hex': '#ff00ff' },
\ { 'color': 14, 'name': 'Aqua', 'hex': '#00ffff' },
\ { 'color': 15, 'name': 'White', 'hex': '#ffffff' },
\ { 'color': 16, 'name': 'Grey0', 'hex': '#000000' },
\ { 'color': 17, 'name': 'NavyBlue', 'hex': '#00005f' },
\ { 'color': 18, 'name': 'DarkBlue', 'hex': '#000087' },
\ { 'color': 19, 'name': 'Blue3', 'hex': '#0000af' },
\ { 'color': 20, 'name': 'Blue3', 'hex': '#0000d7' },
\ { 'color': 21, 'name': 'Blue1', 'hex': '#0000ff' },
\ { 'color': 22, 'name': 'DarkGreen', 'hex': '#005f00' },
\ { 'color': 23, 'name': 'DeepSkyBlue4', 'hex': '#005f5f' },
\ { 'color': 24, 'name': 'DeepSkyBlue4', 'hex': '#005f87' },
\ { 'color': 25, 'name': 'DeepSkyBlue4', 'hex': '#005faf' },
\ { 'color': 26, 'name': 'DodgerBlue3', 'hex': '#005fd7' },
\ { 'color': 27, 'name': 'DodgerBlue2', 'hex': '#005fff' },
\ { 'color': 28, 'name': 'Green4', 'hex': '#008700' },
\ { 'color': 29, 'name': 'SpringGreen4', 'hex': '#00875f' },
\ { 'color': 30, 'name': 'Turquoise4', 'hex': '#008787' },
\ { 'color': 31, 'name': 'DeepSkyBlue3', 'hex': '#0087af' },
\ { 'color': 32, 'name': 'DeepSkyBlue3', 'hex': '#0087d7' },
\ { 'color': 33, 'name': 'DodgerBlue1', 'hex': '#0087ff' },
\ { 'color': 34, 'name': 'Green3', 'hex': '#00af00' },
\ { 'color': 35, 'name': 'SpringGreen3', 'hex': '#00af5f' },
\ { 'color': 36, 'name': 'DarkCyan', 'hex': '#00af87' },
\ { 'color': 37, 'name': 'LightSeaGreen', 'hex': '#00afaf' },
\ { 'color': 38, 'name': 'DeepSkyBlue2', 'hex': '#00afd7' },
\ { 'color': 39, 'name': 'DeepSkyBlue1', 'hex': '#00afff' },
\ { 'color': 40, 'name': 'Green3', 'hex': '#00d700' },
\ { 'color': 41, 'name': 'SpringGreen3', 'hex': '#00d75f' },
\ { 'color': 42, 'name': 'SpringGreen2', 'hex': '#00d787' },
\ { 'color': 43, 'name': 'Cyan3', 'hex': '#00d7af' },
\ { 'color': 44, 'name': 'DarkTurquoise', 'hex': '#00d7d7' },
\ { 'color': 45, 'name': 'Turquoise2', 'hex': '#00d7ff' },
\ { 'color': 46, 'name': 'Green1', 'hex': '#00ff00' },
\ { 'color': 47, 'name': 'SpringGreen2', 'hex': '#00ff5f' },
\ { 'color': 48, 'name': 'SpringGreen1', 'hex': '#00ff87' },
\ { 'color': 49, 'name': 'MediumSpringGreen', 'hex': '#00ffaf' },
\ { 'color': 50, 'name': 'Cyan2', 'hex': '#00ffd7' },
\ { 'color': 51, 'name': 'Cyan1', 'hex': '#00ffff' },
\ { 'color': 52, 'name': 'DarkRed', 'hex': '#5f0000' },
\ { 'color': 53, 'name': 'DeepPink4', 'hex': '#5f005f' },
\ { 'color': 54, 'name': 'Purple4', 'hex': '#5f0087' },
\ { 'color': 55, 'name': 'Purple4', 'hex': '#5f00af' },
\ { 'color': 56, 'name': 'Purple3', 'hex': '#5f00d7' },
\ { 'color': 57, 'name': 'BlueViolet', 'hex': '#5f00ff' },
\ { 'color': 58, 'name': 'Orange4', 'hex': '#5f5f00' },
\ { 'color': 59, 'name': 'Grey37', 'hex': '#5f5f5f' },
\ { 'color': 60, 'name': 'MediumPurple4', 'hex': '#5f5f87' },
\ { 'color': 61, 'name': 'SlateBlue3', 'hex': '#5f5faf' },
\ { 'color': 62, 'name': 'SlateBlue3', 'hex': '#5f5fd7' },
\ { 'color': 63, 'name': 'RoyalBlue1', 'hex': '#5f5fff' },
\ { 'color': 64, 'name': 'Chartreuse4', 'hex': '#5f8700' },
\ { 'color': 65, 'name': 'DarkSeaGreen4', 'hex': '#5f875f' },
\ { 'color': 66, 'name': 'PaleTurquoise4', 'hex': '#5f8787' },
\ { 'color': 67, 'name': 'SteelBlue', 'hex': '#5f87af' },
\ { 'color': 68, 'name': 'SteelBlue3', 'hex': '#5f87d7' },
\ { 'color': 69, 'name': 'CornflowerBlue', 'hex': '#5f87ff' },
\ { 'color': 70, 'name': 'Chartreuse3', 'hex': '#5faf00' },
\ { 'color': 71, 'name': 'DarkSeaGreen4', 'hex': '#5faf5f' },
\ { 'color': 72, 'name': 'CadetBlue', 'hex': '#5faf87' },
\ { 'color': 73, 'name': 'CadetBlue', 'hex': '#5fafaf' },
\ { 'color': 74, 'name': 'SkyBlue3', 'hex': '#5fafd7' },
\ { 'color': 75, 'name': 'SteelBlue1', 'hex': '#5fafff' },
\ { 'color': 76, 'name': 'Chartreuse3', 'hex': '#5fd700' },
\ { 'color': 77, 'name': 'PaleGreen3', 'hex': '#5fd75f' },
\ { 'color': 78, 'name': 'SeaGreen3', 'hex': '#5fd787' },
\ { 'color': 79, 'name': 'Aquamarine3', 'hex': '#5fd7af' },
\ { 'color': 80, 'name': 'MediumTurquoise', 'hex': '#5fd7d7' },
\ { 'color': 81, 'name': 'SteelBlue1', 'hex': '#5fd7ff' },
\ { 'color': 82, 'name': 'Chartreuse2', 'hex': '#5fff00' },
\ { 'color': 83, 'name': 'SeaGreen2', 'hex': '#5fff5f' },
\ { 'color': 84, 'name': 'SeaGreen1', 'hex': '#5fff87' },
\ { 'color': 85, 'name': 'SeaGreen1', 'hex': '#5fffaf' },
\ { 'color': 86, 'name': 'Aquamarine1', 'hex': '#5fffd7' },
\ { 'color': 87, 'name': 'DarkSlateGray2', 'hex': '#5fffff' },
\ { 'color': 88, 'name': 'DarkRed', 'hex': '#870000' },
\ { 'color': 89, 'name': 'DeepPink4', 'hex': '#87005f' },
\ { 'color': 90, 'name': 'DarkMagenta', 'hex': '#870087' },
\ { 'color': 91, 'name': 'DarkMagenta', 'hex': '#8700af' },
\ { 'color': 92, 'name': 'DarkViolet', 'hex': '#8700d7' },
\ { 'color': 93, 'name': 'Purple', 'hex': '#8700ff' },
\ { 'color': 94, 'name': 'Orange4', 'hex': '#875f00' },
\ { 'color': 95, 'name': 'LightPink4', 'hex': '#875f5f' },
\ { 'color': 96, 'name': 'Plum4', 'hex': '#875f87' },
\ { 'color': 97, 'name': 'MediumPurple3', 'hex': '#875faf' },
\ { 'color': 98, 'name': 'MediumPurple3', 'hex': '#875fd7' },
\ { 'color': 99, 'name': 'SlateBlue1', 'hex': '#875fff' },
\ { 'color': 100, 'name': 'Yellow4', 'hex': '#878700' },
\ { 'color': 101, 'name': 'Wheat4', 'hex': '#87875f' },
\ { 'color': 102, 'name': 'Grey53', 'hex': '#878787' },
\ { 'color': 103, 'name': 'LightSlateGrey', 'hex': '#8787af' },
\ { 'color': 104, 'name': 'MediumPurple', 'hex': '#8787d7' },
\ { 'color': 105, 'name': 'LightSlateBlue', 'hex': '#8787ff' },
\ { 'color': 106, 'name': 'Yellow4', 'hex': '#87af00' },
\ { 'color': 107, 'name': 'DarkOliveGreen3', 'hex': '#87af5f' },
\ { 'color': 108, 'name': 'DarkSeaGreen', 'hex': '#87af87' },
\ { 'color': 109, 'name': 'LightSkyBlue3', 'hex': '#87afaf' },
\ { 'color': 110, 'name': 'LightSkyBlue3', 'hex': '#87afd7' },
\ { 'color': 111, 'name': 'SkyBlue2', 'hex': '#87afff' },
\ { 'color': 112, 'name': 'Chartreuse2', 'hex': '#87d700' },
\ { 'color': 113, 'name': 'DarkOliveGreen3', 'hex': '#87d75f' },
\ { 'color': 114, 'name': 'PaleGreen3', 'hex': '#87d787' },
\ { 'color': 115, 'name': 'DarkSeaGreen3', 'hex': '#87d7af' },
\ { 'color': 116, 'name': 'DarkSlateGray3', 'hex': '#87d7d7' },
\ { 'color': 117, 'name': 'SkyBlue1', 'hex': '#87d7ff' },
\ { 'color': 118, 'name': 'Chartreuse1', 'hex': '#87ff00' },
\ { 'color': 119, 'name': 'LightGreen', 'hex': '#87ff5f' },
\ { 'color': 120, 'name': 'LightGreen', 'hex': '#87ff87' },
\ { 'color': 121, 'name': 'PaleGreen1', 'hex': '#87ffaf' },
\ { 'color': 122, 'name': 'Aquamarine1', 'hex': '#87ffd7' },
\ { 'color': 123, 'name': 'DarkSlateGray1', 'hex': '#87ffff' },
\ { 'color': 124, 'name': 'Red3', 'hex': '#af0000' },
\ { 'color': 125, 'name': 'DeepPink4', 'hex': '#af005f' },
\ { 'color': 126, 'name': 'MediumVioletRed', 'hex': '#af0087' },
\ { 'color': 127, 'name': 'Magenta3', 'hex': '#af00af' },
\ { 'color': 128, 'name': 'DarkViolet', 'hex': '#af00d7' },
\ { 'color': 129, 'name': 'Purple', 'hex': '#af00ff' },
\ { 'color': 130, 'name': 'DarkOrange3', 'hex': '#af5f00' },
\ { 'color': 131, 'name': 'IndianRed', 'hex': '#af5f5f' },
\ { 'color': 132, 'name': 'HotPink3', 'hex': '#af5f87' },
\ { 'color': 133, 'name': 'MediumOrchid3', 'hex': '#af5faf' },
\ { 'color': 134, 'name': 'MediumOrchid', 'hex': '#af5fd7' },
\ { 'color': 135, 'name': 'MediumPurple2', 'hex': '#af5fff' },
\ { 'color': 136, 'name': 'DarkGoldenrod', 'hex': '#af8700' },
\ { 'color': 137, 'name': 'LightSalmon3', 'hex': '#af875f' },
\ { 'color': 138, 'name': 'RosyBrown', 'hex': '#af8787' },
\ { 'color': 139, 'name': 'Grey63', 'hex': '#af87af' },
\ { 'color': 140, 'name': 'MediumPurple2', 'hex': '#af87d7' },
\ { 'color': 141, 'name': 'MediumPurple1', 'hex': '#af87ff' },
\ { 'color': 142, 'name': 'Gold3', 'hex': '#afaf00' },
\ { 'color': 143, 'name': 'DarkKhaki', 'hex': '#afaf5f' },
\ { 'color': 144, 'name': 'NavajoWhite3', 'hex': '#afaf87' },
\ { 'color': 145, 'name': 'Grey69', 'hex': '#afafaf' },
\ { 'color': 146, 'name': 'LightSteelBlue3', 'hex': '#afafd7' },
\ { 'color': 147, 'name': 'LightSteelBlue', 'hex': '#afafff' },
\ { 'color': 148, 'name': 'Yellow3', 'hex': '#afd700' },
\ { 'color': 149, 'name': 'DarkOliveGreen3', 'hex': '#afd75f' },
\ { 'color': 150, 'name': 'DarkSeaGreen3', 'hex': '#afd787' },
\ { 'color': 151, 'name': 'DarkSeaGreen2', 'hex': '#afd7af' },
\ { 'color': 152, 'name': 'LightCyan3', 'hex': '#afd7d7' },
\ { 'color': 153, 'name': 'LightSkyBlue1', 'hex': '#afd7ff' },
\ { 'color': 154, 'name': 'GreenYellow', 'hex': '#afff00' },
\ { 'color': 155, 'name': 'DarkOliveGreen2', 'hex': '#afff5f' },
\ { 'color': 156, 'name': 'PaleGreen1', 'hex': '#afff87' },
\ { 'color': 157, 'name': 'DarkSeaGreen2', 'hex': '#afffaf' },
\ { 'color': 158, 'name': 'DarkSeaGreen1', 'hex': '#afffd7' },
\ { 'color': 159, 'name': 'PaleTurquoise1', 'hex': '#afffff' },
\ { 'color': 160, 'name': 'Red3', 'hex': '#d70000' },
\ { 'color': 161, 'name': 'DeepPink3', 'hex': '#d7005f' },
\ { 'color': 162, 'name': 'DeepPink3', 'hex': '#d70087' },
\ { 'color': 163, 'name': 'Magenta3', 'hex': '#d700af' },
\ { 'color': 164, 'name': 'Magenta3', 'hex': '#d700d7' },
\ { 'color': 165, 'name': 'Magenta2', 'hex': '#d700ff' },
\ { 'color': 166, 'name': 'DarkOrange3', 'hex': '#d75f00' },
\ { 'color': 167, 'name': 'IndianRed', 'hex': '#d75f5f' },
\ { 'color': 168, 'name': 'HotPink3', 'hex': '#d75f87' },
\ { 'color': 169, 'name': 'HotPink2', 'hex': '#d75faf' },
\ { 'color': 170, 'name': 'Orchid', 'hex': '#d75fd7' },
\ { 'color': 171, 'name': 'MediumOrchid1', 'hex': '#d75fff' },
\ { 'color': 172, 'name': 'Orange3', 'hex': '#d78700' },
\ { 'color': 173, 'name': 'LightSalmon3', 'hex': '#d7875f' },
\ { 'color': 174, 'name': 'LightPink3', 'hex': '#d78787' },
\ { 'color': 175, 'name': 'Pink3', 'hex': '#d787af' },
\ { 'color': 176, 'name': 'Plum3', 'hex': '#d787d7' },
\ { 'color': 177, 'name': 'Violet', 'hex': '#d787ff' },
\ { 'color': 178, 'name': 'Gold3', 'hex': '#d7af00' },
\ { 'color': 179, 'name': 'LightGoldenrod3', 'hex': '#d7af5f' },
\ { 'color': 180, 'name': 'Tan', 'hex': '#d7af87' },
\ { 'color': 181, 'name': 'MistyRose3', 'hex': '#d7afaf' },
\ { 'color': 182, 'name': 'Thistle3', 'hex': '#d7afd7' },
\ { 'color': 183, 'name': 'Plum2', 'hex': '#d7afff' },
\ { 'color': 184, 'name': 'Yellow3', 'hex': '#d7d700' },
\ { 'color': 185, 'name': 'Khaki3', 'hex': '#d7d75f' },
\ { 'color': 186, 'name': 'LightGoldenrod2', 'hex': '#d7d787' },
\ { 'color': 187, 'name': 'LightYellow3', 'hex': '#d7d7af' },
\ { 'color': 188, 'name': 'Grey84', 'hex': '#d7d7d7' },
\ { 'color': 189, 'name': 'LightSteelBlue1', 'hex': '#d7d7ff' },
\ { 'color': 190, 'name': 'Yellow2', 'hex': '#d7ff00' },
\ { 'color': 191, 'name': 'DarkOliveGreen1', 'hex': '#d7ff5f' },
\ { 'color': 192, 'name': 'DarkOliveGreen1', 'hex': '#d7ff87' },
\ { 'color': 193, 'name': 'DarkSeaGreen1', 'hex': '#d7ffaf' },
\ { 'color': 194, 'name': 'Honeydew2', 'hex': '#d7ffd7' },
\ { 'color': 195, 'name': 'LightCyan1', 'hex': '#d7ffff' },
\ { 'color': 196, 'name': 'Red1', 'hex': '#ff0000' },
\ { 'color': 197, 'name': 'DeepPink2', 'hex': '#ff005f' },
\ { 'color': 198, 'name': 'DeepPink1', 'hex': '#ff0087' },
\ { 'color': 199, 'name': 'DeepPink1', 'hex': '#ff00af' },
\ { 'color': 200, 'name': 'Magenta2', 'hex': '#ff00d7' },
\ { 'color': 201, 'name': 'Magenta1', 'hex': '#ff00ff' },
\ { 'color': 202, 'name': 'OrangeRed1', 'hex': '#ff5f00' },
\ { 'color': 203, 'name': 'IndianRed1', 'hex': '#ff5f5f' },
\ { 'color': 204, 'name': 'IndianRed1', 'hex': '#ff5f87' },
\ { 'color': 205, 'name': 'HotPink', 'hex': '#ff5faf' },
\ { 'color': 206, 'name': 'HotPink', 'hex': '#ff5fd7' },
\ { 'color': 207, 'name': 'MediumOrchid1', 'hex': '#ff5fff' },
\ { 'color': 208, 'name': 'DarkOrange', 'hex': '#ff8700' },
\ { 'color': 209, 'name': 'Salmon1', 'hex': '#ff875f' },
\ { 'color': 210, 'name': 'LightCoral', 'hex': '#ff8787' },
\ { 'color': 211, 'name': 'PaleVioletRed1', 'hex': '#ff87af' },
\ { 'color': 212, 'name': 'Orchid2', 'hex': '#ff87d7' },
\ { 'color': 213, 'name': 'Orchid1', 'hex': '#ff87ff' },
\ { 'color': 214, 'name': 'Orange1', 'hex': '#ffaf00' },
\ { 'color': 215, 'name': 'SandyBrown', 'hex': '#ffaf5f' },
\ { 'color': 216, 'name': 'LightSalmon1', 'hex': '#ffaf87' },
\ { 'color': 217, 'name': 'LightPink1', 'hex': '#ffafaf' },
\ { 'color': 218, 'name': 'Pink1', 'hex': '#ffafd7' },
\ { 'color': 219, 'name': 'Plum1', 'hex': '#ffafff' },
\ { 'color': 220, 'name': 'Gold1', 'hex': '#ffd700' },
\ { 'color': 221, 'name': 'LightGoldenrod2', 'hex': '#ffd75f' },
\ { 'color': 222, 'name': 'LightGoldenrod2', 'hex': '#ffd787' },
\ { 'color': 223, 'name': 'NavajoWhite1', 'hex': '#ffd7af' },
\ { 'color': 224, 'name': 'MistyRose1', 'hex': '#ffd7d7' },
\ { 'color': 225, 'name': 'Thistle1', 'hex': '#ffd7ff' },
\ { 'color': 226, 'name': 'Yellow1', 'hex': '#ffff00' },
\ { 'color': 227, 'name': 'LightGoldenrod1', 'hex': '#ffff5f' },
\ { 'color': 228, 'name': 'Khaki1', 'hex': '#ffff87' },
\ { 'color': 229, 'name': 'Wheat1', 'hex': '#ffffaf' },
\ { 'color': 230, 'name': 'Cornsilk1', 'hex': '#ffffd7' },
\ { 'color': 231, 'name': 'Grey100', 'hex': '#ffffff' },
\ { 'color': 232, 'name': 'Grey3', 'hex': '#080808' },
\ { 'color': 233, 'name': 'Grey7', 'hex': '#121212' },
\ { 'color': 234, 'name': 'Grey11', 'hex': '#1c1c1c' },
\ { 'color': 235, 'name': 'Grey15', 'hex': '#262626' },
\ { 'color': 236, 'name': 'Grey19', 'hex': '#303030' },
\ { 'color': 237, 'name': 'Grey23', 'hex': '#3a3a3a' },
\ { 'color': 238, 'name': 'Grey27', 'hex': '#444444' },
\ { 'color': 239, 'name': 'Grey30', 'hex': '#4e4e4e' },
\ { 'color': 240, 'name': 'Grey35', 'hex': '#585858' },
\ { 'color': 241, 'name': 'Grey39', 'hex': '#626262' },
\ { 'color': 242, 'name': 'Grey42', 'hex': '#6c6c6c' },
\ { 'color': 243, 'name': 'Grey46', 'hex': '#767676' },
\ { 'color': 244, 'name': 'Grey50', 'hex': '#808080' },
\ { 'color': 245, 'name': 'Grey54', 'hex': '#8a8a8a' },
\ { 'color': 246, 'name': 'Grey58', 'hex': '#949494' },
\ { 'color': 247, 'name': 'Grey62', 'hex': '#9e9e9e' },
\ { 'color': 248, 'name': 'Grey66', 'hex': '#a8a8a8' },
\ { 'color': 249, 'name': 'Grey70', 'hex': '#b2b2b2' },
\ { 'color': 250, 'name': 'Grey74', 'hex': '#bcbcbc' },
\ { 'color': 251, 'name': 'Grey78', 'hex': '#c6c6c6' },
\ { 'color': 252, 'name': 'Grey82', 'hex': '#d0d0d0' },
\ { 'color': 253, 'name': 'Grey85', 'hex': '#dadada' },
\ { 'color': 254, 'name': 'Grey89', 'hex': '#e4e4e4' },
\ { 'color': 255, 'name': 'Grey93', 'hex': '#eeeeee' },
\ ]
"----------------------------------------------------------------------
" color index to RGB
"----------------------------------------------------------------------
let g:quickui#palette#rgb = []
let g:quickui#palette#name = {}
let g:quickui#palette#number = get(g:, 'quickui_color_num', 256)
let s:palette = []
let s:matched = {}
let s:names = {}
let s:diff_lookup = repeat([0], 512 * 3)
for color in g:quickui#palette#colors
let cc = str2nr(strpart(color.hex, 1), 16)
let r = and(cc / 0x10000, 0xff)
let g = and(cc / 0x100, 0xff)
let b = and(cc, 0xff)
let g:quickui#palette#rgb += [[r, g, b]]
let s:palette += [[r, g, b]]
let g:quickui#palette#name[tolower(color.name)] = color.color
let s:names[tolower(color.name)] = color.color
endfor
"----------------------------------------------------------------------
" bestfit color
"----------------------------------------------------------------------
function! s:bestfit_color(r, g, b, limit)
if s:diff_lookup[0] == 0
for i in range(256)
let k = i * i
let dr = k * 30 * 30
let dg = k * 59 * 59
let db = k * 11 * 11
let s:diff_lookup[ 256 + i] = dr
let s:diff_lookup[ 256 - i] = dr
let s:diff_lookup[ 768 + i] = dg
let s:diff_lookup[ 768 - i] = dg
let s:diff_lookup[1280 + i] = db
let s:diff_lookup[1280 - i] = db
endfor
let s:diff_lookup[0] = 1
endif
let r = (a:r < 256)? (a:r) : 255
let g = (a:g < 256)? (a:g) : 255
let b = (a:b < 256)? (a:b) : 255
let lowest = 0x7fffffff
let bestfit = 0
let index = 0
let limit = (a:limit < 256)? (a:limit) : 256
let palette = s:palette
let lookup = s:diff_lookup
while index < limit
let rgb = palette[index]
let diff = lookup[ 768 + rgb[1] - g]
if diff < lowest
let diff += lookup[ 256 + rgb[0] - r]
if diff < lowest
let diff += lookup[1280 + rgb[2] - b]
if diff < lowest
let lowest = diff
let bestfit = index
endif
if diff <= 0
break
endif
endif
endif
let index += 1
endwhile
return bestfit
endfunc
"----------------------------------------------------------------------
" find match in 8 colors
"----------------------------------------------------------------------
function! quickui#palette#bestfit8(r, g, b)
return s:bestfit_color(a:r, a:g, a:b, 8)
endfunc
"----------------------------------------------------------------------
" find match in 8 colors
"----------------------------------------------------------------------
function! quickui#palette#bestfit16(r, g, b)
return s:bestfit_color(a:r, a:g, a:b, 16)
endfunc
"----------------------------------------------------------------------
" find match in 8 colors
"----------------------------------------------------------------------
function! quickui#palette#bestfit256(r, g, b)
return s:bestfit_color(a:r, a:g, a:b, 256)
endfunc
"----------------------------------------------------------------------
" consider config
"----------------------------------------------------------------------
function! quickui#palette#bestfit(r, g, b)
return s:bestfit_color(a:r, a:g, a:b, g:quickui#palette#number)
endfunc
"----------------------------------------------------------------------
" matched
"----------------------------------------------------------------------
function! quickui#palette#match(r, g, b)
let r = (a:r < 256)? (a:r) : 255
let g = (a:g < 256)? (a:g) : 255
let b = (a:b < 256)? (a:b) : 255
let key = (r * 4096 / 4) + (g * 64 / 4) + (b / 4)
if !has_key(s:matched, key)
let n = g:quickui#palette#number
let s:matched[key] = s:bestfit_color(a:r, a:g, a:b, n)
endif
return s:matched[key]
endfunc
"----------------------------------------------------------------------
" convert #112233 to [0x11, 0x22, 0x33]
"----------------------------------------------------------------------
function! quickui#palette#hex2rgb(hex)
let [r, g, b] = [0, 0, 0]
let head = strpart(a:hex, 0, 1)
if head == '#'
let cc = str2nr(strpart(a:hex, 1), 16)
let r = and(cc / 0x10000, 0xff)
let g = and(cc / 0x100, 0xff)
let b = and(cc, 0xff)
elseif head == '('
let head = strpart(a:hex, 1, len(a:hex) - 2)
let part = split(head, ',')
let r = str2nr(part[0])
let g = str2nr(part[1])
let b = str2nr(part[2])
endif
return [r, g, b]
endfunc
"----------------------------------------------------------------------
" hex to palette index
"----------------------------------------------------------------------
function! quickui#palette#hex2index(hex)
let [r, g, b] = quickui#palette#hex2rgb(a:hex)
return quickui#palette#match(r, g, b)
endfunc
"----------------------------------------------------------------------
" search name
"----------------------------------------------------------------------
function! quickui#palette#name2index(name, ...)
let head = strpart(a:name, 0, 1)
if head == '#' || head == '('
return quickui#palette#hex2index(a:name)
else
let default = (a:0 < 1)? 0 : (a:1)
let name = tolower(a:name)
if exists('v:colornames')
if has_key(v:colornames, name)
let hex = v:colornames[name]
return quickui#palette#hex2index(hex)
endif
endif
return get(s:names, tolower(a:name), default)
endif
endfunc
"----------------------------------------------------------------------
" alpha blend
"----------------------------------------------------------------------
function! quickui#palette#blend(c1, c2, alpha)
let c1 = a:c1
let c2 = a:c2
let alpha = a:alpha
if type(c1) == 0 && type(c2) == 0
return (c1 * (255 - alpha) + c2 * alpha) / 255
endif
let dst = quickui#palette#hex2rgb(c1)
let src = quickui#palette#hex2rgb(c2)
let r = (dst[0] * (255 - alpha) + src[0] * alpha) / 255
let g = (dst[1] * (255 - alpha) + src[1] * alpha) / 255
let b = (dst[2] * (255 - alpha) + src[2] * alpha) / 255
return printf('#%02x%02x%02x', r, g, b)
endfunc
"----------------------------------------------------------------------
" palette search in desert256
"----------------------------------------------------------------------
" returns an approximate grey index for the given grey level
function! s:grey_number(x)
if &t_Co == 88
if a:x < 23
return 0
elseif a:x < 69
return 1
elseif a:x < 103
return 2
elseif a:x < 127
return 3
elseif a:x < 150
return 4
elseif a:x < 173
return 5
elseif a:x < 196
return 6
elseif a:x < 219
return 7
elseif a:x < 243
return 8
else
return 9
endif
else
if a:x < 14
return 0
else
let l:n = (a:x - 8) / 10
let l:m = (a:x - 8) % 10
if l:m < 5
return l:n
else
return l:n + 1
endif
endif
endif
endfunc
" returns the actual grey level represented by the grey index
function! s:grey_level(n)
if &t_Co == 88
if a:n == 0
return 0
elseif a:n == 1
return 46
elseif a:n == 2
return 92
elseif a:n == 3
return 115
elseif a:n == 4
return 139
elseif a:n == 5
return 162
elseif a:n == 6
return 185
elseif a:n == 7
return 208
elseif a:n == 8
return 231
else
return 255
endif
else
if a:n == 0
return 0
else
return 8 + (a:n * 10)
endif
endif
endfunc
" returns the palette index for the given grey index
function! s:grey_color(n)
if &t_Co == 88
if a:n == 0
return 16
elseif a:n == 9
return 79
else
return 79 + a:n
endif
else
if a:n == 0
return 16
elseif a:n == 25
return 231
else
return 231 + a:n
endif
endif
endfunc
" returns an approximate color index for the given color level
function! s:rgb_number(x)
if &t_Co == 88
if a:x < 69
return 0
elseif a:x < 172
return 1
elseif a:x < 230
return 2
else
return 3
endif
else
if a:x < 75
return 0
else
let l:n = (a:x - 55) / 40
let l:m = (a:x - 55) % 40
if l:m < 20
return l:n
else
return l:n + 1
endif
endif
endif
endfunc
" returns the actual color level for the given color index
function! s:rgb_level(n)
if &t_Co == 88
if a:n == 0
return 0
elseif a:n == 1
return 139
elseif a:n == 2
return 205
else
return 255
endif
else
if a:n == 0
return 0
else
return 55 + (a:n * 40)
endif
endif
endfunc
" returns the palette index for the given R/G/B color indices
function! s:rgb_color(x, y, z)
if &t_Co == 88
return 16 + (a:x * 16) + (a:y * 4) + a:z
else
return 16 + (a:x * 36) + (a:y * 6) + a:z
endif
endfunc
" returns the palette index to approximate the given R/G/B color levels
function! quickui#palette#color_match(r, g, b)
" get the closest grey
let l:gx = s:grey_number(a:r)
let l:gy = s:grey_number(a:g)
let l:gz = s:grey_number(a:b)
" get the closest color
let l:x = s:rgb_number(a:r)
let l:y = s:rgb_number(a:g)
let l:z = s:rgb_number(a:b)
if l:gx == l:gy && l:gy == l:gz
" there are two possibilities
let l:dgr = s:grey_level(l:gx) - a:r
let l:dgg = s:grey_level(l:gy) - a:g
let l:dgb = s:grey_level(l:gz) - a:b
let l:dgrey = (l:dgr * l:dgr) + (l:dgg * l:dgg) + (l:dgb * l:dgb)
let l:dr = s:rgb_level(l:gx) - a:r
let l:dg = s:rgb_level(l:gy) - a:g
let l:db = s:rgb_level(l:gz) - a:b
let l:drgb = (l:dr * l:dr) + (l:dg * l:dg) + (l:db * l:db)
if l:dgrey < l:drgb
" use the grey
return s:grey_color(l:gx)
else
" use the color
return s:rgb_color(l:x, l:y, l:z)
endif
else
" only one possibility
return s:rgb_color(l:x, l:y, l:z)
endif
endfun
function! quickui#palette#rgb_match(rgb) abort
if a:rgb =~ '^#'
let r = ("0x" . strpart(a:rgb, 1, 2)) + 0
let g = ("0x" . strpart(a:rgb, 3, 2)) + 0
let b = ("0x" . strpart(a:rgb, 5, 2)) + 0
else
let r = ("0x" . strpart(a:rgb, 0, 2)) + 0
let g = ("0x" . strpart(a:rgb, 2, 2)) + 0
let b = ("0x" . strpart(a:rgb, 4, 2)) + 0
endif
return quickui#palette#color_match(r, g, b)
endfunc
"----------------------------------------------------------------------
" benchmark
"----------------------------------------------------------------------
function! quickui#palette#timing()
let ts = reltime()
for i in range(256)
call quickui#palette#match(i, i, i)
endfor
let tt = reltime(ts)
return reltimestr(tt)
endfunc
"----------------------------------------------------------------------
" optimize if possible: achieve 40x times faster
"----------------------------------------------------------------------
if has('vim9script')
import './palette9.vim'
function! s:bestfit_color(r, g, b, limit)
return s:palette9.BestfitColor(a:r, a:g, a:b, a:limit)
endfunc
function! quickui#palette#bestfit8(r, g, b)
return s:palette9.Bestfit8(a:r, a:g, a:b)
endfunc
function! quickui#palette#bestfit16(r, g, b)
return s:palette9.Bestfit16(a:r, a:g, a:b)
endfunc
function! quickui#palette#bestfit256(r, g, b)
return s:palette9.Bestfit256(a:r, a:g, a:b)
endfunc
function! quickui#palette#match(r, g, b)
return s:palette9.Match(a:r, a:g, a:b, g:quickui#palette#number)
endfunc
function! quickui#palette#hex2rgb(hex)
return s:palette9.Hex2RGB(a:hex)
endfunc
function! quickui#palette#hex2index(hex)
return s:palette9.Hex2Index(a:hex)
endfunc
function! quickui#palette#name2index(name, ...)
let default = (a:0 == 0)? 0 : (a:1)
return s:palette9.Name2Index(a:name, default)
endfunc
endif

View File

@ -0,0 +1,449 @@
vim9script
#----------------------------------------------------------------------
# terminal palette of 256 colors
#----------------------------------------------------------------------
final color_definition = [
\ { 'color': 0, 'name': 'Black', 'hex': '#000000' },
\ { 'color': 1, 'name': 'Maroon', 'hex': '#800000' },
\ { 'color': 2, 'name': 'Green', 'hex': '#008000' },
\ { 'color': 3, 'name': 'Olive', 'hex': '#808000' },
\ { 'color': 4, 'name': 'Navy', 'hex': '#000080' },
\ { 'color': 5, 'name': 'Purple', 'hex': '#800080' },
\ { 'color': 6, 'name': 'Teal', 'hex': '#008080' },
\ { 'color': 7, 'name': 'Silver', 'hex': '#c0c0c0' },
\ { 'color': 8, 'name': 'Grey', 'hex': '#808080' },
\ { 'color': 9, 'name': 'Red', 'hex': '#ff0000' },
\ { 'color': 10, 'name': 'Lime', 'hex': '#00ff00' },
\ { 'color': 11, 'name': 'Yellow', 'hex': '#ffff00' },
\ { 'color': 12, 'name': 'Blue', 'hex': '#0000ff' },
\ { 'color': 13, 'name': 'Fuchsia', 'hex': '#ff00ff' },
\ { 'color': 14, 'name': 'Aqua', 'hex': '#00ffff' },
\ { 'color': 15, 'name': 'White', 'hex': '#ffffff' },
\ { 'color': 16, 'name': 'Grey0', 'hex': '#000000' },
\ { 'color': 17, 'name': 'NavyBlue', 'hex': '#00005f' },
\ { 'color': 18, 'name': 'DarkBlue', 'hex': '#000087' },
\ { 'color': 19, 'name': 'Blue3', 'hex': '#0000af' },
\ { 'color': 20, 'name': 'Blue3', 'hex': '#0000d7' },
\ { 'color': 21, 'name': 'Blue1', 'hex': '#0000ff' },
\ { 'color': 22, 'name': 'DarkGreen', 'hex': '#005f00' },
\ { 'color': 23, 'name': 'DeepSkyBlue4', 'hex': '#005f5f' },
\ { 'color': 24, 'name': 'DeepSkyBlue4', 'hex': '#005f87' },
\ { 'color': 25, 'name': 'DeepSkyBlue4', 'hex': '#005faf' },
\ { 'color': 26, 'name': 'DodgerBlue3', 'hex': '#005fd7' },
\ { 'color': 27, 'name': 'DodgerBlue2', 'hex': '#005fff' },
\ { 'color': 28, 'name': 'Green4', 'hex': '#008700' },
\ { 'color': 29, 'name': 'SpringGreen4', 'hex': '#00875f' },
\ { 'color': 30, 'name': 'Turquoise4', 'hex': '#008787' },
\ { 'color': 31, 'name': 'DeepSkyBlue3', 'hex': '#0087af' },
\ { 'color': 32, 'name': 'DeepSkyBlue3', 'hex': '#0087d7' },
\ { 'color': 33, 'name': 'DodgerBlue1', 'hex': '#0087ff' },
\ { 'color': 34, 'name': 'Green3', 'hex': '#00af00' },
\ { 'color': 35, 'name': 'SpringGreen3', 'hex': '#00af5f' },
\ { 'color': 36, 'name': 'DarkCyan', 'hex': '#00af87' },
\ { 'color': 37, 'name': 'LightSeaGreen', 'hex': '#00afaf' },
\ { 'color': 38, 'name': 'DeepSkyBlue2', 'hex': '#00afd7' },
\ { 'color': 39, 'name': 'DeepSkyBlue1', 'hex': '#00afff' },
\ { 'color': 40, 'name': 'Green3', 'hex': '#00d700' },
\ { 'color': 41, 'name': 'SpringGreen3', 'hex': '#00d75f' },
\ { 'color': 42, 'name': 'SpringGreen2', 'hex': '#00d787' },
\ { 'color': 43, 'name': 'Cyan3', 'hex': '#00d7af' },
\ { 'color': 44, 'name': 'DarkTurquoise', 'hex': '#00d7d7' },
\ { 'color': 45, 'name': 'Turquoise2', 'hex': '#00d7ff' },
\ { 'color': 46, 'name': 'Green1', 'hex': '#00ff00' },
\ { 'color': 47, 'name': 'SpringGreen2', 'hex': '#00ff5f' },
\ { 'color': 48, 'name': 'SpringGreen1', 'hex': '#00ff87' },
\ { 'color': 49, 'name': 'MediumSpringGreen', 'hex': '#00ffaf' },
\ { 'color': 50, 'name': 'Cyan2', 'hex': '#00ffd7' },
\ { 'color': 51, 'name': 'Cyan1', 'hex': '#00ffff' },
\ { 'color': 52, 'name': 'DarkRed', 'hex': '#5f0000' },
\ { 'color': 53, 'name': 'DeepPink4', 'hex': '#5f005f' },
\ { 'color': 54, 'name': 'Purple4', 'hex': '#5f0087' },
\ { 'color': 55, 'name': 'Purple4', 'hex': '#5f00af' },
\ { 'color': 56, 'name': 'Purple3', 'hex': '#5f00d7' },
\ { 'color': 57, 'name': 'BlueViolet', 'hex': '#5f00ff' },
\ { 'color': 58, 'name': 'Orange4', 'hex': '#5f5f00' },
\ { 'color': 59, 'name': 'Grey37', 'hex': '#5f5f5f' },
\ { 'color': 60, 'name': 'MediumPurple4', 'hex': '#5f5f87' },
\ { 'color': 61, 'name': 'SlateBlue3', 'hex': '#5f5faf' },
\ { 'color': 62, 'name': 'SlateBlue3', 'hex': '#5f5fd7' },
\ { 'color': 63, 'name': 'RoyalBlue1', 'hex': '#5f5fff' },
\ { 'color': 64, 'name': 'Chartreuse4', 'hex': '#5f8700' },
\ { 'color': 65, 'name': 'DarkSeaGreen4', 'hex': '#5f875f' },
\ { 'color': 66, 'name': 'PaleTurquoise4', 'hex': '#5f8787' },
\ { 'color': 67, 'name': 'SteelBlue', 'hex': '#5f87af' },
\ { 'color': 68, 'name': 'SteelBlue3', 'hex': '#5f87d7' },
\ { 'color': 69, 'name': 'CornflowerBlue', 'hex': '#5f87ff' },
\ { 'color': 70, 'name': 'Chartreuse3', 'hex': '#5faf00' },
\ { 'color': 71, 'name': 'DarkSeaGreen4', 'hex': '#5faf5f' },
\ { 'color': 72, 'name': 'CadetBlue', 'hex': '#5faf87' },
\ { 'color': 73, 'name': 'CadetBlue', 'hex': '#5fafaf' },
\ { 'color': 74, 'name': 'SkyBlue3', 'hex': '#5fafd7' },
\ { 'color': 75, 'name': 'SteelBlue1', 'hex': '#5fafff' },
\ { 'color': 76, 'name': 'Chartreuse3', 'hex': '#5fd700' },
\ { 'color': 77, 'name': 'PaleGreen3', 'hex': '#5fd75f' },
\ { 'color': 78, 'name': 'SeaGreen3', 'hex': '#5fd787' },
\ { 'color': 79, 'name': 'Aquamarine3', 'hex': '#5fd7af' },
\ { 'color': 80, 'name': 'MediumTurquoise', 'hex': '#5fd7d7' },
\ { 'color': 81, 'name': 'SteelBlue1', 'hex': '#5fd7ff' },
\ { 'color': 82, 'name': 'Chartreuse2', 'hex': '#5fff00' },
\ { 'color': 83, 'name': 'SeaGreen2', 'hex': '#5fff5f' },
\ { 'color': 84, 'name': 'SeaGreen1', 'hex': '#5fff87' },
\ { 'color': 85, 'name': 'SeaGreen1', 'hex': '#5fffaf' },
\ { 'color': 86, 'name': 'Aquamarine1', 'hex': '#5fffd7' },
\ { 'color': 87, 'name': 'DarkSlateGray2', 'hex': '#5fffff' },
\ { 'color': 88, 'name': 'DarkRed', 'hex': '#870000' },
\ { 'color': 89, 'name': 'DeepPink4', 'hex': '#87005f' },
\ { 'color': 90, 'name': 'DarkMagenta', 'hex': '#870087' },
\ { 'color': 91, 'name': 'DarkMagenta', 'hex': '#8700af' },
\ { 'color': 92, 'name': 'DarkViolet', 'hex': '#8700d7' },
\ { 'color': 93, 'name': 'Purple', 'hex': '#8700ff' },
\ { 'color': 94, 'name': 'Orange4', 'hex': '#875f00' },
\ { 'color': 95, 'name': 'LightPink4', 'hex': '#875f5f' },
\ { 'color': 96, 'name': 'Plum4', 'hex': '#875f87' },
\ { 'color': 97, 'name': 'MediumPurple3', 'hex': '#875faf' },
\ { 'color': 98, 'name': 'MediumPurple3', 'hex': '#875fd7' },
\ { 'color': 99, 'name': 'SlateBlue1', 'hex': '#875fff' },
\ { 'color': 100, 'name': 'Yellow4', 'hex': '#878700' },
\ { 'color': 101, 'name': 'Wheat4', 'hex': '#87875f' },
\ { 'color': 102, 'name': 'Grey53', 'hex': '#878787' },
\ { 'color': 103, 'name': 'LightSlateGrey', 'hex': '#8787af' },
\ { 'color': 104, 'name': 'MediumPurple', 'hex': '#8787d7' },
\ { 'color': 105, 'name': 'LightSlateBlue', 'hex': '#8787ff' },
\ { 'color': 106, 'name': 'Yellow4', 'hex': '#87af00' },
\ { 'color': 107, 'name': 'DarkOliveGreen3', 'hex': '#87af5f' },
\ { 'color': 108, 'name': 'DarkSeaGreen', 'hex': '#87af87' },
\ { 'color': 109, 'name': 'LightSkyBlue3', 'hex': '#87afaf' },
\ { 'color': 110, 'name': 'LightSkyBlue3', 'hex': '#87afd7' },
\ { 'color': 111, 'name': 'SkyBlue2', 'hex': '#87afff' },
\ { 'color': 112, 'name': 'Chartreuse2', 'hex': '#87d700' },
\ { 'color': 113, 'name': 'DarkOliveGreen3', 'hex': '#87d75f' },
\ { 'color': 114, 'name': 'PaleGreen3', 'hex': '#87d787' },
\ { 'color': 115, 'name': 'DarkSeaGreen3', 'hex': '#87d7af' },
\ { 'color': 116, 'name': 'DarkSlateGray3', 'hex': '#87d7d7' },
\ { 'color': 117, 'name': 'SkyBlue1', 'hex': '#87d7ff' },
\ { 'color': 118, 'name': 'Chartreuse1', 'hex': '#87ff00' },
\ { 'color': 119, 'name': 'LightGreen', 'hex': '#87ff5f' },
\ { 'color': 120, 'name': 'LightGreen', 'hex': '#87ff87' },
\ { 'color': 121, 'name': 'PaleGreen1', 'hex': '#87ffaf' },
\ { 'color': 122, 'name': 'Aquamarine1', 'hex': '#87ffd7' },
\ { 'color': 123, 'name': 'DarkSlateGray1', 'hex': '#87ffff' },
\ { 'color': 124, 'name': 'Red3', 'hex': '#af0000' },
\ { 'color': 125, 'name': 'DeepPink4', 'hex': '#af005f' },
\ { 'color': 126, 'name': 'MediumVioletRed', 'hex': '#af0087' },
\ { 'color': 127, 'name': 'Magenta3', 'hex': '#af00af' },
\ { 'color': 128, 'name': 'DarkViolet', 'hex': '#af00d7' },
\ { 'color': 129, 'name': 'Purple', 'hex': '#af00ff' },
\ { 'color': 130, 'name': 'DarkOrange3', 'hex': '#af5f00' },
\ { 'color': 131, 'name': 'IndianRed', 'hex': '#af5f5f' },
\ { 'color': 132, 'name': 'HotPink3', 'hex': '#af5f87' },
\ { 'color': 133, 'name': 'MediumOrchid3', 'hex': '#af5faf' },
\ { 'color': 134, 'name': 'MediumOrchid', 'hex': '#af5fd7' },
\ { 'color': 135, 'name': 'MediumPurple2', 'hex': '#af5fff' },
\ { 'color': 136, 'name': 'DarkGoldenrod', 'hex': '#af8700' },
\ { 'color': 137, 'name': 'LightSalmon3', 'hex': '#af875f' },
\ { 'color': 138, 'name': 'RosyBrown', 'hex': '#af8787' },
\ { 'color': 139, 'name': 'Grey63', 'hex': '#af87af' },
\ { 'color': 140, 'name': 'MediumPurple2', 'hex': '#af87d7' },
\ { 'color': 141, 'name': 'MediumPurple1', 'hex': '#af87ff' },
\ { 'color': 142, 'name': 'Gold3', 'hex': '#afaf00' },
\ { 'color': 143, 'name': 'DarkKhaki', 'hex': '#afaf5f' },
\ { 'color': 144, 'name': 'NavajoWhite3', 'hex': '#afaf87' },
\ { 'color': 145, 'name': 'Grey69', 'hex': '#afafaf' },
\ { 'color': 146, 'name': 'LightSteelBlue3', 'hex': '#afafd7' },
\ { 'color': 147, 'name': 'LightSteelBlue', 'hex': '#afafff' },
\ { 'color': 148, 'name': 'Yellow3', 'hex': '#afd700' },
\ { 'color': 149, 'name': 'DarkOliveGreen3', 'hex': '#afd75f' },
\ { 'color': 150, 'name': 'DarkSeaGreen3', 'hex': '#afd787' },
\ { 'color': 151, 'name': 'DarkSeaGreen2', 'hex': '#afd7af' },
\ { 'color': 152, 'name': 'LightCyan3', 'hex': '#afd7d7' },
\ { 'color': 153, 'name': 'LightSkyBlue1', 'hex': '#afd7ff' },
\ { 'color': 154, 'name': 'GreenYellow', 'hex': '#afff00' },
\ { 'color': 155, 'name': 'DarkOliveGreen2', 'hex': '#afff5f' },
\ { 'color': 156, 'name': 'PaleGreen1', 'hex': '#afff87' },
\ { 'color': 157, 'name': 'DarkSeaGreen2', 'hex': '#afffaf' },
\ { 'color': 158, 'name': 'DarkSeaGreen1', 'hex': '#afffd7' },
\ { 'color': 159, 'name': 'PaleTurquoise1', 'hex': '#afffff' },
\ { 'color': 160, 'name': 'Red3', 'hex': '#d70000' },
\ { 'color': 161, 'name': 'DeepPink3', 'hex': '#d7005f' },
\ { 'color': 162, 'name': 'DeepPink3', 'hex': '#d70087' },
\ { 'color': 163, 'name': 'Magenta3', 'hex': '#d700af' },
\ { 'color': 164, 'name': 'Magenta3', 'hex': '#d700d7' },
\ { 'color': 165, 'name': 'Magenta2', 'hex': '#d700ff' },
\ { 'color': 166, 'name': 'DarkOrange3', 'hex': '#d75f00' },
\ { 'color': 167, 'name': 'IndianRed', 'hex': '#d75f5f' },
\ { 'color': 168, 'name': 'HotPink3', 'hex': '#d75f87' },
\ { 'color': 169, 'name': 'HotPink2', 'hex': '#d75faf' },
\ { 'color': 170, 'name': 'Orchid', 'hex': '#d75fd7' },
\ { 'color': 171, 'name': 'MediumOrchid1', 'hex': '#d75fff' },
\ { 'color': 172, 'name': 'Orange3', 'hex': '#d78700' },
\ { 'color': 173, 'name': 'LightSalmon3', 'hex': '#d7875f' },
\ { 'color': 174, 'name': 'LightPink3', 'hex': '#d78787' },
\ { 'color': 175, 'name': 'Pink3', 'hex': '#d787af' },
\ { 'color': 176, 'name': 'Plum3', 'hex': '#d787d7' },
\ { 'color': 177, 'name': 'Violet', 'hex': '#d787ff' },
\ { 'color': 178, 'name': 'Gold3', 'hex': '#d7af00' },
\ { 'color': 179, 'name': 'LightGoldenrod3', 'hex': '#d7af5f' },
\ { 'color': 180, 'name': 'Tan', 'hex': '#d7af87' },
\ { 'color': 181, 'name': 'MistyRose3', 'hex': '#d7afaf' },
\ { 'color': 182, 'name': 'Thistle3', 'hex': '#d7afd7' },
\ { 'color': 183, 'name': 'Plum2', 'hex': '#d7afff' },
\ { 'color': 184, 'name': 'Yellow3', 'hex': '#d7d700' },
\ { 'color': 185, 'name': 'Khaki3', 'hex': '#d7d75f' },
\ { 'color': 186, 'name': 'LightGoldenrod2', 'hex': '#d7d787' },
\ { 'color': 187, 'name': 'LightYellow3', 'hex': '#d7d7af' },
\ { 'color': 188, 'name': 'Grey84', 'hex': '#d7d7d7' },
\ { 'color': 189, 'name': 'LightSteelBlue1', 'hex': '#d7d7ff' },
\ { 'color': 190, 'name': 'Yellow2', 'hex': '#d7ff00' },
\ { 'color': 191, 'name': 'DarkOliveGreen1', 'hex': '#d7ff5f' },
\ { 'color': 192, 'name': 'DarkOliveGreen1', 'hex': '#d7ff87' },
\ { 'color': 193, 'name': 'DarkSeaGreen1', 'hex': '#d7ffaf' },
\ { 'color': 194, 'name': 'Honeydew2', 'hex': '#d7ffd7' },
\ { 'color': 195, 'name': 'LightCyan1', 'hex': '#d7ffff' },
\ { 'color': 196, 'name': 'Red1', 'hex': '#ff0000' },
\ { 'color': 197, 'name': 'DeepPink2', 'hex': '#ff005f' },
\ { 'color': 198, 'name': 'DeepPink1', 'hex': '#ff0087' },
\ { 'color': 199, 'name': 'DeepPink1', 'hex': '#ff00af' },
\ { 'color': 200, 'name': 'Magenta2', 'hex': '#ff00d7' },
\ { 'color': 201, 'name': 'Magenta1', 'hex': '#ff00ff' },
\ { 'color': 202, 'name': 'OrangeRed1', 'hex': '#ff5f00' },
\ { 'color': 203, 'name': 'IndianRed1', 'hex': '#ff5f5f' },
\ { 'color': 204, 'name': 'IndianRed1', 'hex': '#ff5f87' },
\ { 'color': 205, 'name': 'HotPink', 'hex': '#ff5faf' },
\ { 'color': 206, 'name': 'HotPink', 'hex': '#ff5fd7' },
\ { 'color': 207, 'name': 'MediumOrchid1', 'hex': '#ff5fff' },
\ { 'color': 208, 'name': 'DarkOrange', 'hex': '#ff8700' },
\ { 'color': 209, 'name': 'Salmon1', 'hex': '#ff875f' },
\ { 'color': 210, 'name': 'LightCoral', 'hex': '#ff8787' },
\ { 'color': 211, 'name': 'PaleVioletRed1', 'hex': '#ff87af' },
\ { 'color': 212, 'name': 'Orchid2', 'hex': '#ff87d7' },
\ { 'color': 213, 'name': 'Orchid1', 'hex': '#ff87ff' },
\ { 'color': 214, 'name': 'Orange1', 'hex': '#ffaf00' },
\ { 'color': 215, 'name': 'SandyBrown', 'hex': '#ffaf5f' },
\ { 'color': 216, 'name': 'LightSalmon1', 'hex': '#ffaf87' },
\ { 'color': 217, 'name': 'LightPink1', 'hex': '#ffafaf' },
\ { 'color': 218, 'name': 'Pink1', 'hex': '#ffafd7' },
\ { 'color': 219, 'name': 'Plum1', 'hex': '#ffafff' },
\ { 'color': 220, 'name': 'Gold1', 'hex': '#ffd700' },
\ { 'color': 221, 'name': 'LightGoldenrod2', 'hex': '#ffd75f' },
\ { 'color': 222, 'name': 'LightGoldenrod2', 'hex': '#ffd787' },
\ { 'color': 223, 'name': 'NavajoWhite1', 'hex': '#ffd7af' },
\ { 'color': 224, 'name': 'MistyRose1', 'hex': '#ffd7d7' },
\ { 'color': 225, 'name': 'Thistle1', 'hex': '#ffd7ff' },
\ { 'color': 226, 'name': 'Yellow1', 'hex': '#ffff00' },
\ { 'color': 227, 'name': 'LightGoldenrod1', 'hex': '#ffff5f' },
\ { 'color': 228, 'name': 'Khaki1', 'hex': '#ffff87' },
\ { 'color': 229, 'name': 'Wheat1', 'hex': '#ffffaf' },
\ { 'color': 230, 'name': 'Cornsilk1', 'hex': '#ffffd7' },
\ { 'color': 231, 'name': 'Grey100', 'hex': '#ffffff' },
\ { 'color': 232, 'name': 'Grey3', 'hex': '#080808' },
\ { 'color': 233, 'name': 'Grey7', 'hex': '#121212' },
\ { 'color': 234, 'name': 'Grey11', 'hex': '#1c1c1c' },
\ { 'color': 235, 'name': 'Grey15', 'hex': '#262626' },
\ { 'color': 236, 'name': 'Grey19', 'hex': '#303030' },
\ { 'color': 237, 'name': 'Grey23', 'hex': '#3a3a3a' },
\ { 'color': 238, 'name': 'Grey27', 'hex': '#444444' },
\ { 'color': 239, 'name': 'Grey30', 'hex': '#4e4e4e' },
\ { 'color': 240, 'name': 'Grey35', 'hex': '#585858' },
\ { 'color': 241, 'name': 'Grey39', 'hex': '#626262' },
\ { 'color': 242, 'name': 'Grey42', 'hex': '#6c6c6c' },
\ { 'color': 243, 'name': 'Grey46', 'hex': '#767676' },
\ { 'color': 244, 'name': 'Grey50', 'hex': '#808080' },
\ { 'color': 245, 'name': 'Grey54', 'hex': '#8a8a8a' },
\ { 'color': 246, 'name': 'Grey58', 'hex': '#949494' },
\ { 'color': 247, 'name': 'Grey62', 'hex': '#9e9e9e' },
\ { 'color': 248, 'name': 'Grey66', 'hex': '#a8a8a8' },
\ { 'color': 249, 'name': 'Grey70', 'hex': '#b2b2b2' },
\ { 'color': 250, 'name': 'Grey74', 'hex': '#bcbcbc' },
\ { 'color': 251, 'name': 'Grey78', 'hex': '#c6c6c6' },
\ { 'color': 252, 'name': 'Grey82', 'hex': '#d0d0d0' },
\ { 'color': 253, 'name': 'Grey85', 'hex': '#dadada' },
\ { 'color': 254, 'name': 'Grey89', 'hex': '#e4e4e4' },
\ { 'color': 255, 'name': 'Grey93', 'hex': '#eeeeee' },
\ ]
#----------------------------------------------------------------------
# initialize
#----------------------------------------------------------------------
var _palette: list<list<number>>
var cnames = {}
for color in color_definition
final cc: number = str2nr(strpart(color.hex, 1), 16)
final r: number = and(cc / 0x10000, 0xff)
final g: number = and(cc / 0x100, 0xff)
final b: number = and(cc, 0xff)
final p: list<number> = [r, g, b]
_palette += [p]
cnames[tolower(color.name)] = color.color
endfor
final palette: list<list<number>> = deepcopy(_palette)
var _diff_lookup: list<number> = repeat([0], 512 * 3)
for i in range(256)
final k: number = i * i
final dr: number = k * 30 * 30
final dg: number = k * 59 * 59
final db: number = k * 11 * 11
_diff_lookup[ 256 + i] = dr
_diff_lookup[ 256 - i] = dr
_diff_lookup[ 768 + i] = dg
_diff_lookup[ 768 - i] = dg
_diff_lookup[1280 + i] = db
_diff_lookup[1280 - i] = db
endfor
final diff_lookup: list<number> = deepcopy(_diff_lookup)
#----------------------------------------------------------------------
# bestfit color
#----------------------------------------------------------------------
export def BestfitColor(r: number, g: number, b: number, limit: number = 256): number
final R: number = (r < 256) ? r : 255
final G: number = (g < 256) ? g : 255
final B: number = (b < 256) ? b : 255
final LIMIT: number = (limit < 256) ? limit : 256
final lookup: list<number> = diff_lookup
var lowest = 0x7fffffff
var bestfit = 0
var index = 0
while index < LIMIT
final rgb: list<number> = palette[index]
var diff = lookup[768 + rgb[1] - G]
if diff < lowest
diff += lookup[256 + rgb[0] - R]
if diff < lowest
diff += lookup[1280 + rgb[2] - B]
if diff < lowest
lowest = diff
bestfit = index
endif
if diff <= 0
break
endif
endif
endif
index += 1
endwhile
return bestfit
enddef
#----------------------------------------------------------------------
# for 8 colors
#----------------------------------------------------------------------
export def Bestfit8(r: number, g: number, b: number): number
return BestfitColor(r, g, b, 8)
enddef
#----------------------------------------------------------------------
# for 16 colors
#----------------------------------------------------------------------
export def Bestfit16(r: number, g: number, b: number): number
return BestfitColor(r, g, b, 16)
enddef
#----------------------------------------------------------------------
# for 256 colors
#----------------------------------------------------------------------
export def Bestfit256(r: number, g: number, b: number): number
return BestfitColor(r, g, b, 256)
enddef
#----------------------------------------------------------------------
# for 256 colors
#----------------------------------------------------------------------
var matched = {}
export def Match(r: number, g: number, b: number, num: number = -1): number
final rr = (r < 256) ? r : 255
final gg = (g < 256) ? g : 255
final bb = (b < 256) ? b : 255
final key: number = (rr * 4096 / 4) + (gg * 64 / 4) + (bb / 4)
if !has_key(matched, key)
var N: number = 256
if num >= 0
N = num
else
if exists('g:quickui#palette#number')
N = g:quickui#palette#number
endif
endif
final cc: number = BestfitColor(rr, gg, bb, N)
matched[key] = cc
endif
return matched[key]
enddef
#----------------------------------------------------------------------
# convert #112233 to [0x11, 0x22, 0x33]
#----------------------------------------------------------------------
export def Hex2RGB(hex: string): list<number>
var head: string = strpart(hex, 0, 1)
var r: number = 0
var g: number = 0
var b: number = 0
if head == '#'
final c: number = str2nr(strpart(hex, 1), 16)
r = and(c / 0x10000, 0xff)
g = and(c / 0x100, 0xff)
b = and(c, 0xff)
elseif head == '('
head = strpart(hex, 1, len(hex) - 2)
final part: list<string> = split(head, ',')
r = str2nr(part[0])
g = str2nr(part[1])
b = str2nr(part[2])
endif
return [r, g, b]
enddef
#----------------------------------------------------------------------
# hex to palette index
#----------------------------------------------------------------------
export def Hex2Index(hex: string, num: number = -1): number
final cc: list<number> = Hex2RGB(hex)
return Match(cc[0], cc[1], cc[2], num)
enddef
#----------------------------------------------------------------------
# search name
#----------------------------------------------------------------------
export def Name2Index(name: string, default: number = 0): number
final head = strpart(name, 0, 1)
if head == '#' || head == '('
return Hex2Index(name)
else
final nm = tolower(name)
if exists('v:colornames')
if has_key(v:colornames, nm)
final hex = v:colornames[nm]
return Hex2Index(hex)
endif
endif
return get(cnames, tolower(name), default)
endif
enddef
#----------------------------------------------------------------------
# benchmark
#----------------------------------------------------------------------
export def Timing(): string
var ts = reltime()
for i in range(256)
Match(i, i, i)
endfor
var tt = reltime(ts)
return reltimestr(tt)
enddef

View File

@ -0,0 +1,299 @@
"======================================================================
"
" preview.vim -
"
" Created by skywind on 2020/01/11
" Last Modified: 2021/12/13 22:32
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" private object
"----------------------------------------------------------------------
let s:private = {'winid': -1, 'background': -1, 'state':0}
"----------------------------------------------------------------------
" position to a proper location
"----------------------------------------------------------------------
function! s:around_cursor(width, height)
let cursor_pos = quickui#core#cursor_pos()
let row = cursor_pos[0] - a:height
let col = cursor_pos[1] + 1
if quickui#core#in_screen(row, col, a:width, a:height)
return [row, col]
endif
if col + a:width - 1 > &columns
let col = col - (1 + a:width)
if quickui#core#in_screen(row, col, a:width, a:height)
return [row, col]
endif
endif
if row < 1
let row = row + (1 + a:height)
if quickui#core#in_screen(row, col, a:width, a:height)
return [row, col]
endif
endif
if cursor_pos[0] - a:height - 2 < 1
let row = cursor_pos[0] + 1
else
let row = cursor_pos[0] - a:height
endif
if cursor_pos[1] + a:width + 2 < &columns
let col = cursor_pos[1] + 1
else
let col = cursor_pos[1] - a:width
endif
return quickui#core#screen_fit(row, col, a:width, a:height)
endfunc
"----------------------------------------------------------------------
" create preview window
"----------------------------------------------------------------------
function! quickui#preview#display(content, opts)
call quickui#preview#close()
if type(a:content) == v:t_string && filereadable(a:content) == 0
call quickui#utils#errmsg('E212: Can not open file: '. a:content)
return -1
endif
let s:private.state = 0
if type(a:content) == v:t_string
silent let source = bufadd(a:content)
silent call bufload(source)
elseif type(a:content) == v:t_list
let source = a:content
endif
let winid = -1
let title = ''
if has_key(a:opts, 'title') && (a:opts.title != '')
let title = ' ' . a:opts.title .' '
endif
let w = get(a:opts, 'w', -1)
let h = get(a:opts, 'h', -1)
let w = (w < 0)? 50 : w
let h = (h < 0)? 10 : h
let border = get(a:opts, 'border', g:quickui#style#border)
let button = (get(a:opts, 'close', '') == 'button')? 1 : 0
let color = get(a:opts, 'color', 'QuickPreview')
let p = s:around_cursor(w + (border? 2 : 0), h + (border? 2 : 0))
if has_key(a:opts, 'col')
let p[0] = get(a:opts, 'line', get(a:opts, 'row', 1))
let p[1] = get(a:opts, 'col', 1)
endif
if has('nvim') == 0
let winid = popup_create(source, {'wrap':1, 'mapping':0, 'hidden':1})
let opts = {'maxwidth':w, 'maxheight':h, 'minwidth':w, 'minheight':h}
call popup_move(winid, opts)
let opts = {'close':'button'}
let opts.border = border? [1,1,1,1,1,1,1,1,1] : repeat([0], 9)
let opts.resize = 0
let opts.highlight = color
let opts.borderchars = quickui#core#border_vim(border)
if get(a:opts, 'persist', 0) == 0
let opts.moved = 'any'
endif
let opts.drag = 1
let opts.line = p[0]
let opts.col = p[1]
if title != ''
let opts.title = title
endif
let opts.callback = function('s:popup_exit')
" let opts.fixed = 'true'
if has_key(a:opts, 'bordercolor')
let c = a:opts.bordercolor
let opts.borderhighlight = [c, c, c, c]
endif
call popup_setoptions(winid, opts)
let s:private.winid = winid
call popup_show(winid)
else
let opts = {'focusable':0, 'style':'minimal', 'relative':'editor'}
let opts.width = w
let opts.height = h
let opts.row = p[0]
let opts.col = p[1]
if has_key(a:opts, 'focusable')
let opts.focusable = a:opts.focusable
endif
if type(source) == v:t_number
let bid = source
else
let bid = quickui#core#scratch_buffer('preview', source)
endif
if has('nvim-0.6.0')
let opts.noautocmd = 1
endif
let winid = nvim_open_win(bid, 0, opts)
let s:private.winid = winid
let high = 'Normal:'.color.',NonText:'.color.',EndOfBuffer:'.color
call nvim_win_set_option(winid, 'winhl', high)
let s:private.background = -1
if border > 0 && get(g:, 'quickui_nvim_simulate_border', 1) != 0
let back = quickui#utils#make_border(w, h, border, title, button)
let nbid = quickui#core#scratch_buffer('previewborder', back)
let op = {'relative':'editor', 'focusable':0, 'style':'minimal'}
let op.width = w + 2
let op.height = h + 2
let pos = nvim_win_get_config(winid)
let op.row = pos.row - 1
let op.col = pos.col - 1
let bordercolor = get(a:opts, 'bordercolor', color)
if has('nvim-0.6.0')
let op.noautocmd = 1
endif
let background = nvim_open_win(nbid, 0, op)
call nvim_win_set_option(background, 'winhl', 'Normal:'. bordercolor)
let s:private.background = background
endif
endif
let cmdlist = ['setlocal signcolumn=no norelativenumber']
if get(a:opts, 'number', 1) == 0
let cmdlist += ['setlocal nonumber']
else
let cmdlist += ['setlocal number']
endif
let cursor = get(a:opts, 'cursor', -1)
if cursor > 0
let cmdlist += ['exec "normal! gg' . cursor . 'Gzz"']
endif
if has_key(a:opts, 'syntax')
let cmdlist += ['setl ft=' . fnameescape(a:opts.syntax) ]
endif
let cmdlist += ['silent! setlocal scrolloff=0']
call setbufvar(winbufnr(winid), '__quickui_cursor__', cursor)
call quickui#core#win_execute(winid, cmdlist)
call quickui#utils#update_cursor(winid)
let s:private.state = 1
if has('nvim')
if get(a:opts, 'persist', 0) == 0
autocmd CursorMoved <buffer> ++once call s:autoclose_preview_window()
endif
endif
return winid
endfunc
"----------------------------------------------------------------------
" exit callback
"----------------------------------------------------------------------
function! s:popup_exit(winid, code)
let s:private.winid = -1
let s:private.state = 0
endfunc
"----------------------------------------------------------------------
" close window
"----------------------------------------------------------------------
function! quickui#preview#close()
if s:private.winid >= 0
if has('nvim') == 0
call popup_close(s:private.winid, 0)
let s:private.winid = -1
else
call nvim_win_close(s:private.winid, 0)
let s:private.winid = -1
if s:private.background >= 0
call nvim_win_close(s:private.background, 0)
let s:private.background = -1
endif
endif
endif
let s:private.state = 0
endfunc
"----------------------------------------------------------------------
" return state
"----------------------------------------------------------------------
function! quickui#preview#visible()
return s:private.state
endfunc
"----------------------------------------------------------------------
" quit
"----------------------------------------------------------------------
function! s:autoclose_preview_window()
if s:private.state != 0
if s:private.winid >= 0
call quickui#preview#close()
endif
endif
endfunc
"----------------------------------------------------------------------
" scroll preview window
"----------------------------------------------------------------------
function! quickui#preview#scroll(offset)
if s:private.state != 0
let winid = s:private.winid
if s:private.winid >= 0
noautocmd call quickui#utils#scroll(winid, a:offset)
noautocmd call quickui#utils#update_cursor(winid)
endif
endif
endfunc
"----------------------------------------------------------------------
" press esc to close
"----------------------------------------------------------------------
function! s:press_esc()
exec "nunmap <ESC>"
call quickui#preview#close()
endfunc
"----------------------------------------------------------------------
" preview file
"----------------------------------------------------------------------
function! quickui#preview#open(content, opts)
call quickui#preview#close()
if type(a:content) == v:t_string && filereadable(a:content) == 0
call quickui#utils#errmsg('E484: Cannot open file ' . a:content)
return -1
endif
let opts = {}
let opts.w = get(g:, 'quickui_preview_w', g:quickui#style#preview_w)
let opts.h = get(g:, 'quickui_preview_h', g:quickui#style#preview_h)
let opts.number = get(a:opts, 'number', g:quickui#style#preview_number)
let opts.cursor = get(a:opts, 'cursor', -1)
let title = has_key(a:opts, 'title')? (' ' .. a:opts.title) : ''
if type(a:content) == v:t_string
let name = fnamemodify(a:content, ':p:t')
let opts.title = 'Preview: ' . name . title
else
let opts.title = 'Preview' .. ((title == '')? '' : (':' .. title))
endif
if g:quickui#style#preview_bordercolor != ''
let opts.bordercolor = g:quickui#style#preview_bordercolor
endif
let opts.persist = get(a:opts, 'persist', 0)
let opts.focusable = get(g:, 'quickui_preview_focusable', 1)
if has_key(a:opts, 'syntax')
let opts.syntax = a:opts.syntax
endif
if has_key(a:opts, 'col')
let opts.col = a:opts.col
let opts.line = get(a:opts, 'line', get(a:opts, 'row'))
endif
if has_key(a:opts, 'w')
let opts.w = a:opts.w
let opts.h = get(a:opts, 'h', opts.h)
endif
let hr = quickui#preview#display(a:content, opts)
exec "nnoremap <silent><ESC> :call <SID>press_esc()<cr>"
return hr
endfunc

View File

@ -0,0 +1,914 @@
"======================================================================
"
" readline.vim -
"
" Created by skywind on 2021/02/20
" Last Modified: 2021/11/30 00:04
"
"======================================================================
" vim: set ts=4 sw=4 tw=78 noet :
"----------------------------------------------------------------------
" readline class
"----------------------------------------------------------------------
let s:readline = {}
let s:readline.cursor = 0 " cursur position in character
let s:readline.code = [] " buffer character in int list
let s:readline.wide = [] " char display width
let s:readline.size = 0 " buffer size in character
let s:readline.text = '' " text buffer
let s:readline.dirty = 0 " dirty
let s:readline.select = -1 " visual selection start pos
let s:readline.history = [] " history text
let s:readline.index = 0 " history pointer, 0 for current
let s:readline.timer = -1 " cursor blink timer
"----------------------------------------------------------------------
" move pos
"----------------------------------------------------------------------
function! s:readline.move(pos) abort
let pos = a:pos
let pos = (pos < 0)? 0 : pos
let pos = (pos > self.size)? self.size : pos
let self.cursor = pos
let self.timer = -1
return pos
endfunc
"----------------------------------------------------------------------
" change position, mode: 0/start, 1/current, 2/eol
"----------------------------------------------------------------------
function! s:readline.seek(pos, mode) abort
if a:mode == 0
call self.move(a:pos)
elseif a:mode == 1
call self.move(self.cursor + a:pos)
else
call self.move(self.size + a:pos)
endif
endfunc
"----------------------------------------------------------------------
" set text
"----------------------------------------------------------------------
function! s:readline.set(text)
let code = str2list(a:text)
let wide = []
for cc in code
let ch = nr2char(cc)
let wide += [strdisplaywidth(ch)]
endfor
let self.code = code
let self.wide = wide
let self.size = len(code)
let self.dirty = 1
call self.move(self.cursor)
endfunc
"----------------------------------------------------------------------
" internal: update text parts
"----------------------------------------------------------------------
function! s:readline.update() abort
let self.text = list2str(self.code)
let self.dirty = 0
return self.text
endfunc
"----------------------------------------------------------------------
" slice
"----------------------------------------------------------------------
let s:has_nvim = has('nvim')? 1 : 0
function! s:list_slice(code, start, endup)
let start = a:start
let endup = a:endup
if s:has_nvim == 0
return slice(a:code, a:start, a:endup)
else
if start == endup
return []
else
return a:code[start:endup-1]
endif
endif
endfunc
"----------------------------------------------------------------------
" extract text: -1/0/1 for text before/on/after cursor
"----------------------------------------------------------------------
function! s:readline.extract(locate)
let cc = self.cursor
if a:locate < 0
let p = s:list_slice(self.code, 0, cc)
elseif a:locate == 0
let p = s:list_slice(self.code, cc, cc + 1)
else
let p = s:list_slice(self.code, cc + 1, len(self.code))
endif
return list2str(p)
endfunc
"----------------------------------------------------------------------
" insert text in current cursor position
"----------------------------------------------------------------------
function! s:readline.insert(text) abort
let code = str2list(a:text)
let wide = []
let cursor = self.cursor
for cc in code
let ch = nr2char(cc)
let ww = strwidth(ch)
let wide += [ww]
endfor
call extend(self.code, code, cursor)
call extend(self.wide, wide, cursor)
let self.size = len(self.code)
let self.cursor += len(code)
let self.timer = -1
let self.dirty = 1
endfunc
"----------------------------------------------------------------------
" internal function: delete n characters on and after cursor
"----------------------------------------------------------------------
function! s:readline.delete(size) abort
let cursor = self.cursor
let avail = self.size - cursor
if avail > 0
let size = a:size
let size = (size > avail)? avail : size
let cursor = self.cursor
call remove(self.code, cursor, cursor + size - 1)
call remove(self.wide, cursor, cursor + size - 1)
let self.size = len(self.code)
let self.timer = -1
let self.dirty = 1
endif
endfunc
"----------------------------------------------------------------------
" backspace
"----------------------------------------------------------------------
function! s:readline.backspace(size) abort
let avail = self.cursor
let size = a:size
let size = (size > avail)? avail : size
if size > 0
let self.cursor -= size
call self.delete(size)
let self.timer = -1
let self.dirty = 1
endif
endfunc
"----------------------------------------------------------------------
" replace
"----------------------------------------------------------------------
function! s:readline.replace(text) abort
let length = strchars(a:text)
if length > 0
call self.delete(length)
call self.insert(a:text)
let self.dirty = 1
endif
endfunc
"----------------------------------------------------------------------
" get selection range [start, end)
"----------------------------------------------------------------------
function! s:readline.visual_range() abort
if self.select < 0
return [-1, -1]
elseif self.select <= self.cursor
return [self.select, self.cursor]
else
return [self.cursor, self.select]
endif
endfunc
"----------------------------------------------------------------------
" get selection text
"----------------------------------------------------------------------
function! s:readline.visual_text() abort
if self.select < 0
return ''
else
let [start, end] = self.visual_range()
let code = s:list_slice(self.code, start, end)
return list2str(code)
endif
endfunc
"----------------------------------------------------------------------
" delete selection
"----------------------------------------------------------------------
function! s:readline.visual_delete() abort
if self.select >= 0
let cursor = self.cursor
let length = self.cursor - self.select
if length > 0
call self.backspace(length)
let self.select = -1
elseif length < 0
call self.delete(-length)
let self.select = -1
endif
endif
endfunc
"----------------------------------------------------------------------
" replace selection
"----------------------------------------------------------------------
function! s:readline.visual_replace(text) abort
if self.select >= 0
call self.visual_delete()
call self.insert(a:text)
endif
endfunc
"----------------------------------------------------------------------
" check is eol
"----------------------------------------------------------------------
function! s:readline.is_eol()
return self.cursor >= self.size
endfunc
"----------------------------------------------------------------------
" cursor blink, returns 0 for not blink, 1 for blink (invisible)
"----------------------------------------------------------------------
function! s:readline.blink(millisec)
let delay_wait = 500
let delay_on = 300
let delay_off = 300
if self.timer < 0
let self.timer = a:millisec
return 0
endif
let offset = a:millisec - self.timer
if offset < delay_wait
return 0
else
let size = max([delay_on + delay_off, 1])
return ((offset % size) < delay_on)? 0 : 1
endif
endfunc
"----------------------------------------------------------------------
" read code (what == 0) or wide (what != 0)
"----------------------------------------------------------------------
function! s:readline.read_data(pos, width, what)
let x = a:pos
let w = a:width
let size = self.size
if x < 0
let w += x
let x = 0
endif
if x + w > size
let w = size - x
endif
if x >= size || w <= 0
return []
endif
let data = (a:what == 0)? self.code : self.wide
return s:list_slice(data, x, x + w)
endfunc
"----------------------------------------------------------------------
" calculate available view port size, give length in display-width,
" returns how many characters can fit in length.
"----------------------------------------------------------------------
function! s:readline.avail(pos, length)
let length = a:length
let size = self.size
let wide = self.wide
let pos = a:pos
let sum = 0
if length == 0
return 0
elseif length > 0
while 1
let char_width = (pos >= 0 && pos < size)? wide[pos] : 1
" echo 'pos=' . pos . ' char_width=' . char_width
let sum += char_width
if sum > length
break
endif
let pos += 1
endwhile
return pos - a:pos
else
let length = -length
while 1
let char_width = (pos >= 0 && pos < size)? wide[pos] : 1
let sum += char_width
if sum > length
break
endif
let pos -= 1
endwhile
return a:pos - pos
endif
endfunc
"----------------------------------------------------------------------
" return display width
"----------------------------------------------------------------------
function! s:readline.width(start, endup) abort
let wide = self.wide
let acc = 0
let pos = a:start
let end = a:endup
while pos < end
let acc += wide[pos]
let pos += 1
endwhile
return acc
endfunc
"----------------------------------------------------------------------
" display: returns a list of text string with attributes
" eg. the readline buffer is "Hello, World !!" and cursor is on "W"
" the returns value should be:
" [(0, "Hello, "), (1, "W"), (0, "orld !!")]
" avail attributes: 0/normal-text, 1/cursor, 2/visual, 3/visual+cursor
"----------------------------------------------------------------------
function! s:readline.display() abort
let size = self.size
let cursor = self.cursor
let codes = self.code
let display = []
if (self.select < 0) || (self.select == cursor)
" content before cursor
if cursor > 0
let code = s:list_slice(codes, 0, cursor)
let display += [[0, list2str(code)]]
endif
" content on cursor
let code = (cursor < size)? codes[cursor] : char2nr(' ')
let display += [[1, list2str([code])]]
" content after cursor
if cursor + 1 < size
let code = s:list_slice(codes, cursor + 1, size)
let display += [[0, list2str(code)]]
endif
else
let vis_start = (cursor < self.select)? cursor : self.select
let vis_endup = (cursor > self.select)? cursor : self.select
" content befor visual selection
if vis_start > 0
let code = s:list_slice(codes, 0, vis_start)
let display += [[0, list2str(code)]]
endif
" content in visual selection
if cursor < self.select
let code = [codes[cursor]]
let display += [[3, list2str(code)]]
let code = s:list_slice(codes, cursor + 1, vis_endup)
let display += [[2, list2str(code)]]
if vis_endup < size
let code = s:list_slice(codes, vis_endup, size)
let display += [[0, list2str(code)]]
endif
else
" visual selection
let code = s:list_slice(codes, vis_start, vis_endup)
let display += [[2, list2str(code)]]
" content on cursor
let code = (cursor < size)? codes[cursor] : char2nr(' ')
let display += [[1, list2str([code])]]
" content after cursor
if cursor + 1 < size
let code = s:list_slice(codes, cursor + 1, size)
let display += [[0, list2str(code)]]
endif
endif
endif
return display
endfunc
"----------------------------------------------------------------------
" filter display list with a window
"----------------------------------------------------------------------
function! s:readline.window(display, start, endup) abort
let start = a:start
let endup = a:endup
let display = []
if start < 0
let avail = endup - start
let avail = min([avail, -start])
if avail > 0
let display += [[0, repeat(' ', avail)]]
endif
let start += avail
endif
if start >= endup
return display
endif
let pos = 0
for item in a:display
let attribute = item[0]
let text = item[1]
let chars = strchars(text)
let open = pos
let close = open + chars
if close > start && open < endup
let open = max([open, start])
let open = min([open, endup])
let close = max([close, start])
let close = min([close, endup])
if open < close
if open == pos && close == open + chars
let display += [[attribute, text]]
else
let text = strcharpart(text, open - pos, close - open)
let display += [[attribute, text]]
endif
endif
endif
let pos += chars
endfor
if pos < endup
let display += [[0, repeat(' ', endup - pos)]]
endif
return display
endfunc
"----------------------------------------------------------------------
" returns new window pos to fit in
"----------------------------------------------------------------------
function! s:readline.slide(window_pos, display_width)
let window_pos = a:window_pos
let display_width = a:display_width
let cursor = self.cursor
if display_width < 1
return cursor
elseif cursor < window_pos
return cursor
endif
let window_pos = (window_pos < 0)? 0 : window_pos
let wides = self.read_data(window_pos, cursor - window_pos, 1)
if s:has_nvim == 0
let width = reduce(wides, { acc, val -> acc + val }, 0) + 1
else
let width = 1
for w in wides
let width += w
endfor
endif
if width <= display_width
return window_pos
else
let avail = self.avail(cursor, -display_width)
let pos = cursor - avail + 1
return max([pos, 0])
endif
return window_pos
endfunc
"----------------------------------------------------------------------
" render a window
"----------------------------------------------------------------------
function! s:readline.render(pos, display_width)
let nchars = self.avail(a:pos, a:display_width)
let display = self.display()
let display = self.window(display, a:pos, a:pos + nchars)
let total = 0
for [attr, text] in display
let total += strwidth(text)
endfor
if total < a:display_width
let attr = 0
if self.cursor == a:pos + nchars
let attr = 1
if self.select >= 0
let attr = (self.cursor < self.select)? 3 : 1
endif
else
if self.select > a:pos + nchars
let attr = (self.cursor < a:pos + nchars)? 2 : 0
endif
endif
let display += [[attr, repeat(' ', a:display_width - total)]]
endif
return display
endfunc
"----------------------------------------------------------------------
" calculate mouse click position
"----------------------------------------------------------------------
function! s:readline.mouse_click(winpos, offset)
let index = self.avail(a:winpos, a:offset) + a:winpos
return (index > self.size)? self.size : index
endfunc
"----------------------------------------------------------------------
" save history in current position
"----------------------------------------------------------------------
function! s:readline.history_save() abort
let size = len(self.history)
if size > 0
let self.index = (self.index < 0)? 0 : self.index
let self.index = (self.index >= size)? (size - 1) : self.index
if self.dirty
call self.update()
endif
let self.history[self.index] = self.text
endif
endfunc
"----------------------------------------------------------------------
" previous history
"----------------------------------------------------------------------
function! s:readline.history_prev() abort
let size = len(self.history)
if size > 0
call self.history_save()
let self.index = (self.index < size - 1)? (self.index + 1) : 0
call self.set(self.history[self.index])
call self.update()
endif
endfunc
"----------------------------------------------------------------------
" next history
"----------------------------------------------------------------------
function! s:readline.history_next() abort
let size = len(self.history)
if size > 0
call self.history_save()
let self.index = (self.index <= 0)? (size - 1) : (self.index - 1)
call self.set(self.history[self.index])
call self.update()
endif
endfunc
"----------------------------------------------------------------------
" init history
"----------------------------------------------------------------------
function! s:readline.history_init(history) abort
if len(a:history) == 0
let self.history = []
let self.index = 0
else
let history = deepcopy(a:history) + ['']
call reverse(history)
let self.history = history
let self.index = 0
endif
endfunc
"----------------------------------------------------------------------
" feed character
"----------------------------------------------------------------------
function! s:readline.feed(char) abort
let char = a:char
let code = str2list(char)
let head = len(code)? code[0] : 0
if head < 0x20 || head == 0x80
if char == "\<BS>"
if self.select >= 0
call self.visual_delete()
else
call self.backspace(1)
endif
elseif char == "\<DELETE>"
if self.select >= 0
call self.visual_delete()
else
call self.delete(1)
endif
elseif char == "\<LEFT>" || char == "\<c-b>"
if self.select >= 0
call self.move(min([self.select, self.cursor]))
let self.select = -1
else
call self.seek(-1, 1)
endif
elseif char == "\<RIGHT>" || char == "\<c-f>"
if self.select >= 0
call self.move(max([self.select, self.cursor]))
let self.select = -1
else
call self.seek(1, 1)
endif
elseif char == "\<UP>"
call self.history_prev()
let self.select = -1
elseif char == "\<DOWN>"
call self.history_next()
let self.select = -1
elseif char == "\<S-Left>"
if self.select < 0
let self.select = self.cursor
endif
call self.seek(-1, 1)
elseif char == "\<S-Right>"
if self.select < 0
let self.select = self.cursor
endif
call self.seek(1, 1)
elseif char == "\<S-Home>"
if self.select < 0
let self.select = self.cursor
endif
call self.seek(0, 0)
elseif char == "\<S-End>"
if self.select < 0
let self.select = self.cursor
endif
call self.seek(0, 2)
elseif char == "\<c-d>"
if self.select >= 0
call self.visual_delete()
else
call self.delete(1)
endif
elseif char == "\<c-k>"
if self.select >= 0
call self.visual_delete()
else
if self.size > self.cursor
call self.delete(self.size - self.cursor)
endif
endif
elseif char == "\<home>" || char == "\<c-a>"
call self.move(0)
let self.select = -1
elseif char == "\<end>" || char == "\<c-e>"
call self.move(self.size)
let self.select = -1
elseif char == "\<C-Insert>"
if self.select >= 0
let text = self.visual_text()
if text != ''
let @* = text
endif
endif
elseif char == "\<S-Insert>"
let text = split(@*, "\n", 1)[0]
let text = substitute(text, '[\r\n\t]', ' ', 'g')
if text != ''
if self.select >= 0
call self.visual_delete()
endif
call self.insert(text)
endif
elseif char == "\<c-w>"
if self.select < 0
let head = self.extract(-1)
let word = matchstr(head, '\S\+\s*$')
if word != ''
call self.backspace(strchars(word))
endif
else
call self.visual_delete()
endif
elseif char == "\<c-c>"
if self.select >= 0
let text = self.visual_text()
if text != ''
let @0 = text
endif
endif
elseif char == "\<c-x>"
if self.select >= 0
let text = self.visual_text()
if text != ''
let @0 = text
call self.visual_delete()
endif
endif
elseif char == "\<c-v>"
let text = split(@0, "\n", 1)[0]
let text = substitute(text, '[\r\n\t]', ' ', 'g')
if text != ''
if self.select >= 0
call self.visual_delete()
endif
call self.insert(text)
endif
else
return -1
endif
return 0
else
if self.select >= 0
call self.visual_delete()
endif
call self.insert(char)
endif
return 0
endfunc
"----------------------------------------------------------------------
" display parts
"----------------------------------------------------------------------
function! s:readline.echo(blink, ...)
if a:0 < 2
let display = self.render(0, self.size * 4)
else
let display = self.render(a:1, a:2)
endif
for [attr, text] in display
if attr == 0
echohl Normal
elseif attr == 1
if a:blink == 0
echohl Cursor
else
echohl Normal
endif
elseif attr == 2
echohl Visual
elseif attr == 3
if a:blink == 0
echohl Cursor
else
echohl Visual
endif
endif
echon text
endfor
endfunc
"----------------------------------------------------------------------
" constructor
"----------------------------------------------------------------------
function! quickui#readline#new()
let obj = deepcopy(s:readline)
return obj
endfunc
"----------------------------------------------------------------------
" test suit
"----------------------------------------------------------------------
function! quickui#readline#test()
let v:errors = []
let obj = quickui#readline#new()
call obj.set('0123456789')
call assert_equal('0123456789', obj.update(), 'test set')
call obj.insert('ABC')
call assert_equal('ABC0123456789', obj.update(), 'test insert')
call obj.delete(3)
call assert_equal('ABC3456789', obj.update(), 'test delete')
call obj.backspace(2)
call assert_equal('A3456789', obj.update(), 'test backspace')
call obj.delete(1000)
call assert_equal('A', obj.update(), 'test kill right')
call obj.insert('BCD')
call assert_equal('ABCD', obj.update(), 'test append')
call obj.delete(1000)
call assert_equal('ABCD', obj.update(), 'test append')
call obj.backspace(1000)
call assert_equal('', obj.update(), 'test append')
call obj.insert('0123456789')
call assert_equal('0123456789', obj.update(), 'test reinit')
call obj.move(3)
call obj.replace('abcd')
call assert_equal('012abcd789', obj.update(), 'test replace')
let obj.select = obj.cursor
call obj.seek(-2, 1)
call obj.visual_delete()
call assert_equal('012ab789', obj.update(), 'test visual delete')
let obj.select = obj.cursor
call obj.seek(2, 1)
echo obj.display()
call assert_equal('78', obj.visual_text(), 'test visual selection')
call obj.visual_delete()
call assert_equal('012ab9', obj.update(), 'test visual delete2')
call obj.seek(-2, 1)
if len(v:errors)
for error in v:errors
echoerr error
endfor
endif
call obj.move(1)
let obj.select = 4
echo obj.display()
return obj.update()
endfunc
" echo quickui#readline#test()
"----------------------------------------------------------------------
" cli test
"----------------------------------------------------------------------
function! quickui#readline#cli(prompt)
let rl = quickui#readline#new()
let rl.history = ['', 'abcd', '12345']
let index = 0
let accept = ''
let pos = 0
while 1
noautocmd redraw
echohl Question
echon a:prompt
let ts = float2nr(reltimefloat(reltime()) * 1000)
if 0
call rl.echo(rl.blink(ts))
else
let size = 10
let pos = rl.slide(pos, size)
echohl Title
echon "<"
call rl.echo(rl.blink(ts), pos, size)
echohl Title
echon ">"
echon " size=" . size
echon " cursor=" . rl.cursor
echon " pos=". pos
echon " blink=". rl.blink(ts)
echon " avail=". rl.avail(pos, size)
endif
" echon rl.display()
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<c-c>"
endtry
if type(code) == v:t_number && code == 0
try
exec 'sleep 15m'
continue
catch /^Vim:Interrupt$/
let code = "\<c-c>"
endtry
endif
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == ""
continue
elseif ch == "\<ESC>"
break
elseif ch == "\<cr>"
let accept = rl.update()
break
else
call rl.feed(ch)
endif
endwhile
echohl None
noautocmd redraw
echo ""
return accept
endfunc
"----------------------------------------------------------------------
" testing suit
"----------------------------------------------------------------------
if 0
let suit = 0
if suit == 0
call quickui#readline#test()
elseif suit == 1
let rl = quickui#readline#new()
call rl.insert('abad')
echo rl.mouse_click(0, 5)
elseif suit == 2
echo quickui#readline#cli(">>> ")
elseif suit == 3
let rl = quickui#readline#new()
let size = 10
echo "avail=" . rl.avail(0, size)
call rl.insert("hello")
echo "cursor=" . rl.cursor
echo "avail=" . rl.avail(0, size)
endif
endif

View File

@ -0,0 +1,22 @@
"======================================================================
"
" style.vim -
"
" Created by skywind on 2019/12/19
" Last Modified: 2019/12/19 16:06:59
"
"======================================================================
"----------------------------------------------------------------------
" default border style: 1/ascii, 2/single, 3/double
"----------------------------------------------------------------------
let g:quickui#style#border = get(g:, 'quickui#style#border', 1)
let g:quickui#style#tip_head = '[tip]'
let g:quickui#style#preview_w = 85
let g:quickui#style#preview_h = 10
let g:quickui#style#preview_number = 1
let g:quickui#style#preview_bordercolor = ''

View File

@ -0,0 +1,340 @@
"======================================================================
"
" terminal.vim -
"
" Created by skywind on 2020/02/03
" Last Modified: 2020/02/03 10:31:33
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" terminal return
"----------------------------------------------------------------------
let g:quickui#terminal#capture = []
let g:quickui#terminal#tmpname = ''
"----------------------------------------------------------------------
" create a terminal popup
"----------------------------------------------------------------------
function! quickui#terminal#create(cmd, opts)
let w = get(a:opts, 'w', 80)
let h = get(a:opts, 'h', 24)
let winid = -1
let title = has_key(a:opts, 'title')? (' ' . a:opts.title .' ') : ''
let border = get(a:opts, 'border', g:quickui#style#border)
let button = (get(a:opts, 'close', '') == 'button')? 1 : 0
let color = get(a:opts, 'color', 'QuickTermBorder')
let ww = w + ((border != 0)? 2 : 0)
let hh = h + ((border != 0)? 2 : 0)
let hwnd = {'opts':deepcopy(a:opts), 'code':-1}
if !has_key(hwnd.opts, 'line')
let limit1 = (&lines - 2) * 90 / 100
let limit2 = (&lines - 2)
if h + 4 < limit1
let hwnd.opts.line = (limit1 - hh) / 2
else
let hwnd.opts.line = (limit2 - hh) / 2
endif
let hwnd.opts.line = (hwnd.opts.line < 1)? 1 : hwnd.opts.line
endif
if !has_key(hwnd.opts, 'col')
let hwnd.opts.col = (&columns - ww) / 2
let hwnd.opts.col = (hwnd.opts.col < 1)? 1 : hwnd.opts.col
endif
if has('nvim') == 0
let opts = {'hidden': 1, 'term_rows':h, 'term_cols':w}
let opts.term_kill = get(a:opts, 'term_kill', 'term')
let opts.norestore = 1
let opts.exit_cb = function('s:vim_term_exit')
let opts.term_finish = 'close'
let savedir = getcwd()
if has_key(a:opts, 'cwd')
call quickui#core#chdir(a:opts.cwd)
endif
let bid = term_start(a:cmd, opts)
if has_key(a:opts, 'cwd')
call quickui#core#chdir(savedir)
endif
if bid <= 0
return -1
endif
let opts = {'maxwidth':w, 'maxheight':h, 'minwidth':w, 'minheight':h}
let opts.wrap = 0
let opts.mapping = 0
let opts.title = title
let opts.close = (button)? 'button' : 'none'
let opts.border = border? [1,1,1,1,1,1,1,1,1] : repeat([0], 9)
let opts.highlight = color
let opts.borderchars = quickui#core#border_vim(border)
let opts.drag = get(a:opts, 'drag', 1)
let opts.resize = 0
let opts.callback = function('s:vim_popup_callback')
let winid = popup_create(bid, opts)
call popup_move(winid, {'line':hwnd.opts.line, 'col':hwnd.opts.col})
let hwnd.winid = winid
let g:quickui#terminal#current = hwnd
let s:current = hwnd
call popup_show(winid)
let init = []
let init += ['setlocal nonumber norelativenumber scrolloff=0']
let init += ['setlocal signcolumn=no']
let init += ['setlocal bufhidden=wipe']
call quickui#core#win_execute(winid, init)
else
let bid = quickui#core#scratch_buffer('terminal', [])
let opts = {'focusable':1, 'style':'minimal', 'relative':'editor'}
let opts.width = w
let opts.height = h
let opts.row = hwnd.opts.line - 1 + ((border > 0)? 1 : 0)
let opts.col = hwnd.opts.col - 1 + ((border > 0)? 1 : 0)
if has('nvim-0.6.0')
let opts.noautocmd = 1
endif
let winid = nvim_open_win(bid, 1, opts)
let hwnd.winid = winid
let hwnd.background = -1
if winid < 0
return -1
endif
let cc = get(g:, 'terminal_color_0', 0)
let hl = 'Normal:'.cc.',NonText:'.cc.',EndOfBuffer:'.cc
" silent! call nvim_win_set_option(winid, 'winhl', hl)
call setwinvar(winid, '&winhighlight', 'NormalFloat:Normal')
if border > 0
let title = has_key(a:opts, 'title')? ' ' . a:opts.title . ' ':''
let back = quickui#utils#make_border(w, h, border, title, button)
let nbid = quickui#core#scratch_buffer('terminalborder', back)
let op = {'relative':'editor', 'focusable':0, 'style':'minimal'}
let op.width = w + 2
let op.height = h + 2
let pos = nvim_win_get_config(winid)
let op.row = hwnd.opts.line - 1
let op.col = hwnd.opts.col - 1
if has('nvim-0.6.0')
let op.noautocmd = 1
endif
let background = nvim_open_win(nbid, 0, op)
call nvim_win_set_option(background, 'winhl', 'Normal:'. color)
let hwnd.background = background
endif
call nvim_set_current_win(winid)
setlocal nomodified
let opts = {'width': w, 'height':h}
let opts.on_exit = function('s:nvim_term_exit')
if has_key(a:opts, 'cwd')
let opts.cwd = a:opts.cwd
endif
call termopen(a:cmd, opts)
let g:quickui#terminal#current = hwnd
let s:current = hwnd
let init = []
let init += ['setlocal nonumber norelativenumber scrolloff=0']
let init += ['setlocal signcolumn=no']
let init += ['setlocal bufhidden=wipe']
call quickui#core#win_execute(winid, init)
startinsert
endif
return hwnd
endfunc
"----------------------------------------------------------------------
" read back capture
"----------------------------------------------------------------------
function! s:capture_read()
let g:quickui#terminal#capture = []
if g:quickui#terminal#tmpname != ''
let tmpname = g:quickui#terminal#tmpname
let g:quickui#terminal#tmpname = ''
if filereadable(tmpname)
silent! let g:quickui#terminal#capture = readfile(tmpname)
call delete(tmpname)
endif
endif
endfunc
"----------------------------------------------------------------------
" terminal exit_cb
"----------------------------------------------------------------------
function! s:vim_term_exit(job, message)
if exists('s:current')
let hwnd = s:current
let hwnd.code = a:message
endif
endfunc
"----------------------------------------------------------------------
" popup callback
"----------------------------------------------------------------------
function! s:vim_popup_callback(winid, code)
if exists('s:current')
let hwnd = s:current
let hwnd.winid = -1
call s:capture_read()
if has_key(hwnd.opts, 'callback')
call call(hwnd.opts.callback, [hwnd.code])
endif
endif
endfunc
"----------------------------------------------------------------------
" neovim exit
"----------------------------------------------------------------------
function! s:nvim_term_exit(jobid, data, event)
if exists('s:current')
let hwnd = s:current
let hwnd.code = a:data
if hwnd.winid >= 0
call nvim_win_close(hwnd.winid, 0)
endif
if hwnd.background >= 0
call nvim_win_close(hwnd.background, 0)
endif
let hwnd.winid = -1
let hwnd.background = -1
call s:capture_read()
if has_key(hwnd.opts, 'callback')
call call(hwnd.opts.callback, [hwnd.code])
endif
endif
endfunc
"----------------------------------------------------------------------
" open terminal in popup window
"----------------------------------------------------------------------
function! quickui#terminal#open(cmd, opts)
let opts = deepcopy(a:opts)
let border = get(a:opts, 'border', g:quickui#style#border)
if border == 0
if has_key(opts, 'title')
unlet opts['title']
endif
if has_key(opts, 'close')
unlet opts['close']
endif
endif
if has_key(opts, 'callback')
if type(opts.callback) == v:t_string
if opts.callback == ''
unlet opts['callback']
endif
endif
endif
if has_key(opts, 'w')
let opts.w = quickui#utils#read_size(opts.w, &columns)
endif
if has_key(opts, 'h')
let opts.h = quickui#utils#read_size(opts.h, &lines)
endif
let g:quickui#terminal#capture = []
let g:quickui#terminal#tmpname = ''
let $VIM_INPUT = ''
let $VIM_CAPTURE = ''
if has_key(opts, 'input')
if has('win32') || has('win64') || has('win95') || has('win16')
let tmpname = fnamemodify(tempname(), ':h') . '\quickui1.txt'
else
let tmpname = fnamemodify(tempname(), ':h') . '/quickui1.txt'
endif
call writefile(opts.input, tmpname)
let $VIM_INPUT = tmpname
endif
if has_key(opts, 'capture')
if opts.capture
if has('win32') || has('win64') || has('win95') || has('win16')
let tmpname = fnamemodify(tempname(), ':h') . '\quickui2.txt'
else
let tmpname = fnamemodify(tempname(), ':h') . '/quickui2.txt'
endif
let g:quickui#terminal#tmpname = tmpname
let $VIM_CAPTURE = tmpname
if filereadable(tmpname)
call delete(tmpname)
endif
endif
unlet opts['capture']
endif
return quickui#terminal#create(a:cmd, opts)
endfunc
"----------------------------------------------------------------------
" dialog exit
"----------------------------------------------------------------------
function! s:dialog_callback(code)
let args = {}
let args.code = a:code
let args.capture = g:quickui#terminal#capture
call call(s:dialog_cb, [args])
endfunc
"----------------------------------------------------------------------
" dialog: run command line tool and capture result
" the callback function changes to a new prototype:
" function! Callback(args), where args is a tuple of (code, capture)
" where capture is a list of text lines in the $VIM_CAPTURE file
"----------------------------------------------------------------------
function! quickui#terminal#dialog(cmd, opts)
let opts = deepcopy(a:opts)
let opts.macros = quickui#core#expand_macros()
if has_key(opts, 'prepare')
call call(opts.prepare, [opts])
endif
let command = a:cmd
for [key, val] in items(opts.macros)
let replace = (key[0] != '<')? '$('.key.')' : key
if key[0] != '<'
exec 'let $' . key . ' = val'
endif
let command = quickui#core#string_replace(command, replace, val)
if has_key(opts, 'cwd')
let opts.cwd = quickui#core#string_replace(opts.cwd, replace, val)
endif
endfor
let cwd = get(opts, 'cwd', '')
if cwd != ''
let previous = getcwd()
call quickui#core#chdir(cwd)
let opts.macros['VIM_CWD'] = getcwd()
let opts.macros['VIM_RELDIR'] = expand("%:h:.")
let opts.macros['VIM_RELNAME'] = expand("%:p:.")
let opts.macros['VIM_CFILE'] = expand("<cfile>")
let opts.macros['VIM_DIRNAME'] = fnamemodify(opts.macros['VIM_CWD'], ':t')
let opts.macros['<cwd>'] = opts.macros['VIM_CWD']
call quickui#core#chdir(previous)
endif
let pause = get(opts, 'pause', 0)
let command = quickui#core#write_script(command, pause)
if has_key(opts, 'callback')
let l:F2 = opts.callback
if type(l:F2) == v:t_string
if l:F2 != ''
let s:dialog_cb = function(l:F2)
let opts.callback = function('s:dialog_callback')
let opts.capture = 1
endif
elseif type(l:F2) == v:t_func
let s:dialog_cb = function(l:F2)
let opts.callback = function('s:dialog_callback')
let opts.capture = 1
endif
unlet l:F2
endif
if has_key(opts, 'cwd')
if opts.cwd == ''
unlet opts['cwd']
endif
endif
return quickui#terminal#open(command, opts)
endfunc

View File

@ -0,0 +1,452 @@
"======================================================================
"
" textbox.vim -
"
" Created by skywind on 2019/12/27
" Last Modified: 2020/02/20 02:29
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" reposition
"----------------------------------------------------------------------
function! quickui#textbox#reposition()
let curline = line('.')
exec 'normal! zz'
let height = winheight(0)
let moveup = winline() - 1
if moveup > 0
exec "normal " . moveup . "\<c-e>"
exec ":" . curline
endif
let size = line('$')
let winline = winline()
let topline = curline - winline + 1
let botline = topline + height - 1
let disline = botline - size
if disline > 0
exec 'normal ggG'
exec ':' . curline
exec 'normal G'
exec ':' . curline
endif
endfunc
"----------------------------------------------------------------------
" create textbox
"----------------------------------------------------------------------
function! s:vim_create_textbox(textlist, opts)
let winid = popup_create(a:textlist, {'hidden':1, 'wrap':1})
let opts = {}
let opts.maxheight = &lines - 2
let opts.maxwidth = &columns
if has_key(a:opts, 'w')
let opts.minwidth = a:opts.w
let opts.maxwidth = a:opts.w
endif
if has_key(a:opts, 'h')
let opts.minheight = a:opts.h
let opts.maxheight = a:opts.h
endif
if has_key(a:opts, 'line') && has_key(a:opts, 'col')
let opts.line = a:opts.line
let opts.col = a:opts.col
endif
if len(opts) > 0
call popup_move(winid, opts)
endif
if has_key(a:opts, 'line') == 0 || has_key(a:opts, 'col') == 0
call quickui#utils#center(winid)
endif
let opts = {'mapping':0, 'cursorline':0, 'drag':1}
let border = get(a:opts, 'border', g:quickui#style#border)
let opts.border = [0,0,0,0,0,0,0,0,0]
if border > 0
let opts.borderchars = quickui#core#border_vim(border)
let opts.border = [1,1,1,1,1,1,1,1,1]
let opts.close = 'button'
endif
let opts.padding = [0,1,0,1]
if has_key(a:opts, 'title') && (a:opts.title != '')
let opts.title = ' '. a:opts.title . ' '
endif
let opts.filter = function('s:popup_filter')
let opts.callback = function('s:popup_exit')
let opts.resize = get(a:opts, 'resize', 0)
let opts.highlight = get(a:opts, 'color', 'QuickBG')
if has_key(a:opts, 'index')
let index = (a:opts.index < 1)? 1 : a:opts.index
let opts.firstline = index
call win_execute(winid, ':' . index)
endif
let local = quickui#core#popup_local(winid)
let local.winid = winid
let local.keymap = quickui#utils#keymap()
let local.keymap['x'] = 'ESC'
let local.opts = deepcopy(a:opts)
if has_key(a:opts, 'callback')
let local.callback = a:opts.callback
endif
if has_key(a:opts, 'list')
if a:opts.list
call win_execute(winid, 'setl list')
else
call win_execute(winid, 'setl nolist')
endif
endif
let bc = get(a:opts, 'bordercolor', 'QuickBorder')
let opts.borderhighlight = [bc, bc, bc, bc]
if has_key(a:opts, 'tabstop')
call win_execute(winid, 'setlocal tabstop=' . get(a:opts, 'tabstop', 4))
endif
if has_key(a:opts, 'syntax')
call win_execute(winid, 'set ft=' . fnameescape(a:opts.syntax))
endif
let cursor = get(a:opts, 'cursor', -1)
call setbufvar(winbufnr(winid), '__quickui_cursor__', cursor)
call setbufvar(winbufnr(winid), '__quickui_line__', -1)
if get(a:opts, 'number', 0) != 0
call win_execute(winid, 'setlocal number')
endif
if cursor < 0
call win_execute(winid, 'setlocal nocursorline')
endif
if has_key(a:opts, 'bordercolor')
let c = a:opts.bordercolor
let opts.borderhighlight = [c, c, c, c]
endif
call popup_setoptions(winid, opts)
call win_execute(winid, 'setlocal scrolloff=0')
if has_key(a:opts, 'command')
call quickui#core#win_execute(winid, a:opts.command)
endif
call quickui#utils#update_cursor(winid)
call popup_show(winid)
redraw
return winid
endfunc
"----------------------------------------------------------------------
" close textbox
"----------------------------------------------------------------------
function! quickui#textbox#close(winid)
call popup_close(a:winid)
endfunc
"----------------------------------------------------------------------
" exit and quit
"----------------------------------------------------------------------
function! s:popup_exit(winid, code)
let topline = quickui#utils#get_topline(a:winid)
let g:quickui#textbox#topline = topline
let local = quickui#core#popup_local(a:winid)
let g:quickui#textbox#current = local
call quickui#core#popup_clear(a:winid)
if has_key(local, 'callback')
let l:F = function(local.callback)
call l:F(topline)
unlet l:F
endif
endfunc
"----------------------------------------------------------------------
" filter
"----------------------------------------------------------------------
function! s:popup_filter(winid, key)
let local = quickui#core#popup_local(a:winid)
let keymap = local.keymap
if a:key == "\<ESC>" || a:key == "\<C-C>" || a:key == "\<cr>"
call popup_close(a:winid, 0)
return 1
elseif a:key == " " || a:key == "x" || a:key == "q"
call popup_close(a:winid, 0)
return 1
elseif a:key == "\<LeftMouse>"
let pos = getmousepos()
if pos.winid == a:winid && pos.line > 0
if get(local.opts, 'exit_on_click', 0) != 0
call popup_close(a:winid, 0)
return 1
endif
endif
elseif a:key == ':' || a:key == '/' || a:key == '?'
call quickui#utils#search_or_jump(a:winid, a:key)
noautocmd call quickui#utils#update_cursor(a:winid)
redraw
return 1
elseif has_key(keymap, a:key)
let key = keymap[a:key]
if key == "ENTER" || key == "ESC"
call popup_close(a:winid, 0)
return 1
elseif key == 'NEXT' || key == 'PREV'
call quickui#utils#search_next(a:winid, key)
noautocmd call quickui#utils#update_cursor(a:winid)
redraw
return 1
else
noautocmd call quickui#utils#scroll(a:winid, key)
redraw
noautocmd call quickui#utils#update_cursor(a:winid)
endif
endif
return popup_filter_yesno(a:winid, a:key)
endfunc
"----------------------------------------------------------------------
" create text box in neovim
"----------------------------------------------------------------------
function! s:nvim_create_textbox(textlist, opts)
if type(a:textlist) == v:t_list
let bid = quickui#core#scratch_buffer('textbox', a:textlist)
elseif type(a:textlist) == v:t_string
let bid = quickui#core#scratch_buffer('textbox', [a:textlist])
elseif type(a:textlist) == v:t_number
let bid = a:textlist
endif
let opts = {'focusable':1, 'style':'minimal', 'relative':'editor'}
let opts.width = get(a:opts, 'w', 80)
let opts.height = get(a:opts, 'h', 24)
let opts.row = get(a:opts, 'line', 1) - 1
let opts.col = get(a:opts, 'col', 1) - 1
let border = get(a:opts, 'border', g:quickui#style#border)
if border > 0 && get(g:, 'quickui_nvim_simulate_border', 1) != 0
let opts.row += 1
let opts.col += 1
endif
if has('nvim-0.6.0')
let opts.noautocmd = 1
endif
let winid = nvim_open_win(bid, 0, opts)
if has_key(a:opts, 'line') == 0 && has_key(a:opts, 'col') == 0
call quickui#utils#center(winid)
endif
let color = get(a:opts, 'color', 'QuickBG')
call nvim_win_set_option(winid, 'winhl', 'Normal:'. color)
let opts.w = nvim_win_get_width(winid)
let opts.h = nvim_win_get_height(winid)
let button = (get(a:opts, 'close', '') == 'button')? 1 : 0
let background = -1
if border > 0 && get(g:, 'quickui_nvim_simulate_border', 1) != 0
let title = has_key(a:opts, 'title')? ' ' . a:opts.title . ' ' : ''
let w = opts.w
let h = opts.h
let back = quickui#utils#make_border(w, h, border, title, button)
let nbid = quickui#core#scratch_buffer('textboxborder', back)
let op = {'relative':'editor', 'focusable':1, 'style':'minimal'}
let op.width = opts.w + 2
let op.height = opts.h + 2
let pos = nvim_win_get_config(winid)
let op.row = pos.row - 1
let op.col = pos.col - 1
let bordercolor = get(a:opts, 'bordercolor', 'QuickBorder')
if has('nvim-0.6.0')
let op.noautocmd = 1
endif
let background = nvim_open_win(nbid, 0, op)
call nvim_win_set_option(background, 'winhl', 'Normal:'. bordercolor)
endif
let init = ['syn clear']
if has_key(a:opts, 'tabstop')
let init += ['setlocal tabstop='. get(a:opts, 'tabstop', 4)]
endif
let init += ['setlocal signcolumn=no']
let init += ['setlocal scrolloff=0']
let init += ['setlocal wrap']
let init += ['noautocmd exec "normal! gg"']
if get(a:opts, 'number', 0) != 0
let init += ['setlocal number']
endif
if has_key(a:opts, 'syntax')
let init += ['set ft='.fnameescape(a:opts.syntax)]
" echo "syntax: ". a:opts.syntax
endif
let cursor = get(a:opts, 'cursor', -1)
call setbufvar(bid, '__quickui_cursor__', cursor)
call setbufvar(bid, '__quickui_line__', -1)
if has_key(a:opts, 'index')
let index = (a:opts.index < 1)? 1 : a:opts.index
let opts.firstline = index
let init += ['noautocmd exec "normal! gg"']
if index > 1
let init += ['noautocmd exec "normal! '. (index - 1) . '\<c-e>"']
endif
endif
call quickui#core#win_execute(winid, init)
let highlight = 'Normal:'.color.',NonText:'.color.',EndOfBuffer:'.color
call nvim_win_set_option(winid, 'winhl', highlight)
if has_key(a:opts, 'command')
call quickui#core#win_execute(winid, a:opts.command)
endif
noautocmd call quickui#utils#update_cursor(winid)
let local = {}
let local.winid = winid
let local.keymap = quickui#utils#keymap()
let local.keymap['x'] = 'ESC'
let local.opts = deepcopy(a:opts)
noautocmd redraw
while 1
noautocmd redraw!
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<ESC>" || ch == "\<c-c>"
break
elseif ch == ' ' || ch == 'x' || ch == 'q'
break
elseif ch == "\<LeftMouse>"
if v:mouse_winid == winid
if v:mouse_lnum > 0
if get(a:opts, 'exit_on_click', 0) != 0
break
endif
endif
elseif v:mouse_winid == background
if button != 0 && v:mouse_lnum == 1
if v:mouse_col == opts.w + 2
break
endif
endif
endif
elseif ch == '/' || ch == '?' || ch == ':'
call quickui#utils#search_or_jump(winid, ch)
noautocmd call quickui#utils#update_cursor(winid)
elseif has_key(local.keymap, ch)
let key = local.keymap[ch]
if key == 'ENTER' || key == 'ESC'
break
elseif key == 'NEXT' || key == 'PREV'
call quickui#utils#search_next(winid, key)
noautocmd call quickui#utils#update_cursor(winid)
else
noautocmd call quickui#utils#scroll(winid, key)
noautocmd call quickui#utils#update_cursor(winid)
endif
endif
endwhile
let topline = quickui#utils#get_topline(winid)
let g:quickui#textbox#topline = topline
call nvim_win_close(winid, 0)
if background >= 0
call nvim_win_close(background, 0)
endif
let g:quickui#textbox#current = local
if has_key(a:opts, 'callback')
let F = function(a:opts.callback)
call F(topline)
endif
return topline
endfunc
"----------------------------------------------------------------------
" cross platform create
"----------------------------------------------------------------------
function! quickui#textbox#create(textlist, opts)
if g:quickui#core#has_nvim == 0
return s:vim_create_textbox(a:textlist, a:opts)
else
return s:nvim_create_textbox(a:textlist, a:opts)
endif
endfunc
"----------------------------------------------------------------------
" open
"----------------------------------------------------------------------
function! quickui#textbox#open(textlist, opts)
let maxheight = (&lines) * 70 / 100
let maxwidth = (&columns) * 80 / 100
let opts = deepcopy(a:opts)
let opts.close = 'button'
let maxheight = has_key(opts, 'maxheight')? opts.maxheight : maxheight
let maxwidth = has_key(opts, 'maxwidth')? opts.maxwidth : maxwidth
if has_key(opts, 'h') == 0
let size = (type(a:textlist) == v:t_list)? len(a:textlist) : 20
let opts.h = (size < maxheight)? size : maxheight
endif
if has_key(opts, 'w') == 0
if type(a:textlist) == v:t_list
let opts.w = 1
for line in a:textlist
let size = strdisplaywidth(line)
let opts.w = (size < opts.w)? opts.w : size
endfor
if opts.w > maxwidth
let opts.w = maxwidth
endif
if get(a:opts, 'number', 0) != 0
let opts.w += len(string(len(a:textlist))) + 3
endif
endif
endif
if has_key(opts, 'h')
let minheight = get(opts, 'minheight', 1)
let minheight = (minheight < 1)? 1 : minheight
let opts.h = (opts.h < minheight)? minheight : opts.h
endif
if has_key(opts, 'w')
let minwidth = get(opts, 'minwidth', 20)
let minwidth = (minwidth < 1)? 1 : minwidth
let opts.w = (opts.w < minwidth)? minwidth : opts.w
endif
call quickui#textbox#create(a:textlist, opts)
endfunc
"----------------------------------------------------------------------
" run shell command and display result in the text box
"----------------------------------------------------------------------
function! quickui#textbox#command(cmd, opts)
let text = quickui#utils#system(a:cmd)
let linelist = []
let enc = get(g:, 'quickui_shell_encoding', '')
for line in split(text, "\n")
if enc != ''
let line = iconv(line, enc, &encoding)
endif
let line = trim(line, "\r")
let linelist += [line]
endfor
call quickui#textbox#open(linelist, a:opts)
endfunc
"----------------------------------------------------------------------
" testing suit
"----------------------------------------------------------------------
if 0
let lines = []
for i in range(2000)
let lines += ['printf("%d\n", ' . (i + 1) . ');']
endfor
let opts = {}
let opts.index = 30
let opts.resize = 1
let opts.title = "title"
let opts.syntax = "cpp"
let opts.color = "QuickBox"
let opts.border = 0
" let opts.bordercolor = "QuickBG"
let opts.cursor = 38
let opts.number = 1
" let opts.exit_on_click = 0
let winid = quickui#textbox#open(lines, opts)
" call getchar()
" call quickui#textbox#close(winid)
endif

View File

@ -0,0 +1,523 @@
"======================================================================
"
" tools.vim -
"
" Created by skywind on 2019/12/23
" Last Modified: 2021/11/30 14:43
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" list buffer ids
"----------------------------------------------------------------------
function! s:buffer_list()
let l:ls_cli = get(g:, 'quickui_buffer_list_cli', 'ls t')
redir => buflist
silent execute l:ls_cli
redir END
let bids = []
for curline in split(buflist, '\n')
if curline =~ '^\s*\d\+'
let bid = str2nr(matchstr(curline, '^\s*\zs\d\+'))
let bids += [bid]
endif
endfor
return bids
endfunc
"----------------------------------------------------------------------
" get default width
"----------------------------------------------------------------------
function! s:get_tools_width()
let width = get(g:, 'quickui_tools_width', 70)
endfunc
"----------------------------------------------------------------------
" locals
"----------------------------------------------------------------------
let s:keymaps = '123456789abcdefimnopqrstuvwxyz'
"----------------------------------------------------------------------
" switch buffer callback
"----------------------------------------------------------------------
function! quickui#tools#buffer_switch(bid)
let switch = get(g:, 'quickui_switch_mode', &switchbuf)
let code = g:quickui#listbox#current.tag
let name = fnamemodify(bufname(a:bid), ':p')
let opts = {}
let bid = str2nr('' . a:bid)
if code == ''
let opts.switch = get(g:, 'quickui_switch_enter', switch)
call quickui#utils#switch(bid, opts)
elseif code == '1'
let opts.switch = get(g:, 'quickui_switch_space', switch)
call quickui#utils#switch(bid, opts)
elseif code == '2'
exec 'b '. a:bid
elseif code == '3'
exec 'vs'
exec 'b '. a:bid
elseif code == '4'
exec 'split'
exec 'b '. a:bid
elseif code == '5'
exec 'tab split'
exec 'b '. a:bid
elseif code == '6'
exec 'tab drop ' . fnameescape(name)
endif
endfunc
"----------------------------------------------------------------------
" get content
"----------------------------------------------------------------------
function! quickui#tools#list_buffer(switch)
let bids = s:buffer_list()
let content = []
let index = 0
let current = -1
let bufnr = bufnr()
let s:switch = a:switch
for bid in bids
let key = (index < len(s:keymaps))? strpart(s:keymaps, index, 1) : ''
let text = '[' . ((key == '')? ' ' : ('&' . key)) . "]\t"
let text .= "\t"
let name = fnamemodify(bufname(bid), ':p')
let main = fnamemodify(name, ':t')
let path = fnamemodify(name, ':h')
let buftype = getbufvar(bid, '&buftype')
if main == ''
continue
elseif buftype == 'nofile' || buftype == 'quickfix'
continue
endif
let text = text . main . " " . "(" . bid . ")\t" . path
let cmd = 'call quickui#tools#buffer_switch(' . bid . ')'
if a:switch != ''
" let cmd = a:switch . ' ' . fnameescape(name)
endif
let content += [[text, cmd]]
if bid == bufnr()
let current = index
endif
let index += 1
endfor
let opts = {'title': 'Switch Buffer', 'index':current, 'close':'button'}
let opts.border = g:quickui#style#border
let opts.keymap = {}
let opts.keymap["\<space>"] = 'TAG:1'
let opts.keymap["\<c-e>"] = 'TAG:2'
let opts.keymap["\<c-]>"] = 'TAG:3'
let opts.keymap["\<c-x>"] = 'TAG:4'
let opts.keymap["\<c-t>"] = 'TAG:5'
let opts.keymap["\<c-g>"] = 'TAG:6'
if exists('g:quickui_tools_width')
let opts.w = quickui#utils#tools_width()
endif
" let opts.syntax = 'cpp'
let maxheight = (&lines) * 60 / 100
if len(content) > maxheight
let opts.h = maxheight
endif
if len(content) == 0
redraw
echohl ErrorMsg
echo "Empty buffer list"
echohl None
return -1
endif
call quickui#listbox#open(content, opts)
endfunc
"----------------------------------------------------------------------
" list function
"----------------------------------------------------------------------
function! quickui#tools#list_function()
let ctags = get(g:, 'quickui_ctags_exe', 'ctags')
if !executable(ctags)
let msg = 'Not find ctags, add to $PATH or specify in '
call quickui#utils#errmsg(msg . 'g:quickui_ctags_exe')
return -1
endif
let items = quickui#tags#function_list(bufnr(), &ft)
if len(items) == 0
call quickui#utils#errmsg('No content !')
return -2
endif
let content = []
let cursor = -1
let index = 0
let ln = line('.')
let maxsize = (&columns) * 60 / 100
let maxheight = (&lines) * 60 / 100
let maxwidth = 0
let indents = get(g:, 'quickui_tags_indent', {})
for item in items
if ln >= item.line
let cursor = index
endif
let index += 1
let space = get(indents, item.mode, '')
let text = '' . item.mode . '' . " \t" . space . item.text
let text = text . ' [:' . item.line . ']'
let maxwidth = (maxwidth < len(text))? len(text) : maxwidth
let text = substitute(text, '&', '&&', 'g')
let content += [[text, ':' . item.line]]
endfor
let opts = {'title': 'Function List', 'close':'button'}
if cursor >= 0
let opts.index = cursor
endif
let limit = &columns * 90 / 100
let opts.h = len(content)
let opts.h = (opts.h < maxheight)? opts.h : maxheight
let opts.w = (maxwidth < limit)? maxwidth : limit
if opts.w < maxsize
let opts.w = (opts.w < 60)? 60 : opts.w
endif
let opts.syntax = 'qui_func'
if exists('g:quickui_tools_width')
let opts.w = quickui#utils#tools_width()
endif
" let content += ["1\t".repeat('0', 100)]
call quickui#listbox#open(content, opts)
return 0
endfunc
"----------------------------------------------------------------------
" preview register in popup and choose to paste
"----------------------------------------------------------------------
function! quickui#tools#list_register()
endfunc
"----------------------------------------------------------------------
" display python help in the textbox
"----------------------------------------------------------------------
function! quickui#tools#python_help(word)
let python = get(g:, 'quickui_tools_python', '')
if python == ''
if executable('python')
let python = 'python'
elseif executable('python3')
let python = 'python3'
elseif executable('python2')
let python = 'python2'
endif
endif
if a:word == ''
let text = getline('.')
let pre = text[:col('.') - 1]
let suf = text[col('.'):]
let word = matchstr(pre, "[A-Za-z0-9_.]*$")
let word = word . matchstr(suf, "^[A-Za-z0-9_]*")
else
let word = a:word
endif
let cmd = python . ' -m pydoc ' . shellescape(word)
let title = 'PyDoc <'. a:word . '>'
let opts = {'title':title}
let opts.color = 'QuickBG'
" let opts.bordercolor = 'QuickBG'
let opts.tabstop = 12
call quickui#textbox#command(cmd, opts)
endfunc
"----------------------------------------------------------------------
" display messages
"----------------------------------------------------------------------
function! quickui#tools#display_messages()
let x = ''
redir => x
silent! messages
redir END
let x = substitute(x, '[\n\r]\+\%$', '', 'g')
let content = filter(split(x, "\n"), 'v:key != ""')
if len(content) == 0
call quickui#utils#errmsg('Empty messages')
return -1
endif
let opts = {"close":"button", "title":"Vim Messages"}
if exists('g:quickui_tools_width')
let opts.w = quickui#utils#tools_width()
endif
call quickui#textbox#open(content, opts)
endfunc
"----------------------------------------------------------------------
" preview quickfix
"----------------------------------------------------------------------
function! quickui#tools#preview_quickfix(...)
if quickui#preview#visible()
call quickui#preview#close()
return 0
endif
if &bt != 'quickfix'
call quickui#utils#errmsg('Not in quickfix window !')
return -1
endif
if !exists('b:__quickui_qf__')
let b:__quickui_qf__ = {}
endif
let obj = b:__quickui_qf__
if !has_key(obj, 'version')
let obj.version = -1
endif
if b:changedtick != obj.version
if getwininfo(win_getid())[0].loclist != 0
let obj.items = getloclist(0)
else
let obj.items = getqflist()
endif
let obj.version = b:changedtick
endif
let index = (a:0 > 0)? a:1 : line('.')
if index < 1 || index > len(obj.items)
call quickui#utils#errmsg('No information in this line')
return -2
endif
let item = obj.items[index - 1]
if item.valid == 0
return -3
endif
if item.bufnr <= 0
return -4
endif
let name = bufname(item.bufnr)
let opts = {'cursor':item.lnum}
call quickui#preview#open(name, opts)
" echom 'lnum:'. item.lnum
endfunc
"----------------------------------------------------------------------
" preview tag
"----------------------------------------------------------------------
function! quickui#tools#preview_tag(tagname)
let tagname = (a:tagname == '')? expand('<cword>') : a:tagname
if tagname == ''
call quickui#utils#errmsg('Error: empty tagname')
return 0
endif
let obj = quickui#core#object(0)
let reuse = 0
if has_key(obj, 'ptag')
let ptag = obj.ptag
if get(ptag, 'tagname', '') == tagname
let reuse = 1
endif
endif
if reuse == 0
let obj.ptag = {}
let ptag = obj.ptag
let ptag.taglist = quickui#tags#tagfind(tagname)
let ptag.tagname = tagname
let ptag.index = 0
else
let ptag = obj.ptag
let ptag.index += 1
if ptag.index >= len(ptag.taglist)
let ptag.index = 0
endif
endif
if len(ptag.taglist) == 0
call quickui#utils#errmsg('E257: preview: tag not find "' . tagname . '"')
return 1
endif
if ptag.index >= len(ptag.taglist) || ptag.index < 0
let ptag.index = 0
endif
let taginfo = ptag.taglist[ptag.index]
let filename = taginfo.filename
if !filereadable(filename)
call quickui#utils#errmsg('E484: Can not open file '.filename)
return 2
endif
if !has_key(taginfo, 'line')
call quickui#utils#errmsg('Error: no "line" information in your tags, regenerate with -n')
return 3
endif
let text = '('.(ptag.index + 1).'/'.len(ptag.taglist).')'
let opts = {'cursor':taginfo.line, 'title':text}
call quickui#preview#open(filename, opts)
let text = taginfo.name
let text.= ' ('.(ptag.index + 1).'/'.len(ptag.taglist).') '
let text.= filename
if has_key(taginfo, 'line')
let text .= ':'.taginfo.line
endif
let display = has('gui_running')? 0 : 1
let display = get(g:, 'quickui_preview_tag_msg', display)
if display != 0
call quickui#utils#print(text, 1)
endif
return 0
endfunc
"----------------------------------------------------------------------
" display vim help in popup
"----------------------------------------------------------------------
function! quickui#tools#display_help(tag)
if !exists('s:help_tags')
let fn = expand('$VIMRUNTIME/doc/tags')
if filereadable(fn)
let content = readfile(fn)
let s:help_tags = {}
for line in content
let parts = split(line, "\t")
if len(parts) >= 3
let s:help_tags[parts[0]] = [parts[1], parts[2]]
endif
endfor
endif
endif
if !exists('s:help_tags')
call quickui#utils#errmsg('Sorry, not find help tags in $VIMRUNTIME')
return -1
endif
if !has_key(s:help_tags, a:tag)
call quickui#utils#errmsg('E149: Sorry, no help for '. a:tag)
return -2
endif
let item = s:help_tags[a:tag]
let name = expand($VIMRUNTIME . '/doc/' . item[0])
let command = substitute(item[1], '\*', '', 'g')
if !filereadable(name)
call quickui#utils#errmsg('E484: Sorry, cannot open file '.name)
return -3
endif
let content = readfile(name)
let opts = {'syntax':'help', 'color':'QuickPreview', 'close':'button'}
let opts.title = 'Help: ' . fnamemodify(name, ':t')
let g:quickui#tools#hint = item[1]
let opts.command = ['silent! exec g:quickui#tools#hint']
let opts.command += ["exec 'nohl'"]
let opts.command += ["normal zz"]
let opts.w = 80
" echom opts
let winid = quickui#textbox#open(content, opts)
return 0
endfunc
"----------------------------------------------------------------------
" save curses help
"----------------------------------------------------------------------
let s:previous_cursor = {}
function! s:remember_cursor_context(code)
let hwnd = g:quickui#context#current
let name = hwnd.opts.keep_name
let s:previous_cursor[name] = g:quickui#context#cursor
endfunc
function! s:remember_cursor_listbox(code)
let hwnd = g:quickui#listbox#current
let name = hwnd.opts.keep_name
let s:previous_cursor[name] = g:quickui#listbox#cursor
endfunc
function! quickui#tools#clever_context(name, content, opts)
let opts = deepcopy(a:opts)
let opts.index = get(s:previous_cursor, a:name, -1)
let opts.keep_name = a:name
let opts.callback = function('s:remember_cursor_context')
let content = quickui#context#reduce_items(a:content)
call quickui#context#open_nested(content, opts)
endfunc
function! quickui#tools#clever_listbox(name, content, opts)
let opts = deepcopy(a:opts)
let opts.index = get(s:previous_cursor, a:name, -1)
let opts.keep_name = a:name
let opts.callback = function('s:remember_cursor_listbox')
call quickui#listbox#open(a:content, opts)
endfunc
"----------------------------------------------------------------------
" terminal
"----------------------------------------------------------------------
function! quickui#tools#terminal(name)
if !exists('g:quickui_terminal_tools')
let g:quickui_terminal_tools = {}
endif
if !has_key(g:quickui_terminal_tools, a:name)
call quickui#utils#errmsg('ERROR: tool ' . a:name . ' not defined !')
return -1
endif
let tools = g:quickui_terminal_tools[a:name]
if !has_key(tools, 'cmd')
call quickui#utils#errmsg('ERROR: key cmd not present in tool ' . a:name)
return -1
endif
let opts = {}
let cmd = tools.cmd
let w = get(g:, 'quickui_terminal_w', 80)
let h = get(g:, 'quickui_terminal_h', 24)
let opts.w = get(tools, 'w', w)
let opts.h = get(tools, 'h', h)
if has_key(tools, 'color')
if tools.color != ''
let opts.color = tools.color
endif
endif
if has_key(tools, 'title')
let opts.title = tools.title
endif
if has_key(tools, 'callback')
let opts.callback = tools.callback
endif
if has_key(tools, 'prepare')
let opts.prepare = tools.prepare
endif
if has_key(tools, 'cwd')
let opts.cwd = tools.cwd
endif
if has_key(tools, 'script')
let opts.safe = tools.script
endif
if has_key(tools, 'pause')
if tools.pause
let opts.pause = 1
endif
endif
if has_key(tools, 'close')
if tools.close
let opts.close = 1
endif
endif
call quickui#terminal#dialog(cmd, opts)
return 0
endfunc
"----------------------------------------------------------------------
" search inputbox
"----------------------------------------------------------------------
function! quickui#tools#input_search()
let cword = expand('<cword>')
let title = 'Enter text to search:'
let text = quickui#input#open(title, cword, 'search')
redraw
if text != ''
let text = escape(text, '[\/*~^.')
call feedkeys("\<ESC>/" . text . "\<cr>", 'n')
endif
endfunc

View File

@ -0,0 +1,914 @@
"======================================================================
"
" utils.vim -
"
" Created by skywind on 2019/12/19
" Last Modified: 2023/07/23 18:44
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
"----------------------------------------------------------------------
" parse description into item object
"----------------------------------------------------------------------
function! quickui#utils#item_parse(description)
let obj = {'text':'', 'key_pos':-1, 'key_char':'', 'is_sep':0, 'help':''}
let text = ''
let child = 0
if type(a:description) == v:t_string
let text = a:description
let obj.help = ''
let obj.cmd = ''
elseif type(a:description) == v:t_list
let size = len(a:description)
let text = (size >= 1)? a:description[0] : ''
let obj.help = (size >= 3)? a:description[2] : ''
let obj.cmd = ''
if size >= 2
if type(a:description[1]) == v:t_string
let obj.cmd = a:description[1]
elseif type(a:description[1]) == v:t_list
let obj.cmd = ''
let obj.child = a:description[1]
let child = 1
endif
endif
endif
if text =~ '^-\+$'
let obj.is_sep = 1
let obj.text = ""
let obj.desc = ""
let obj.text_width = 0
let obj.desc_width = 0
let obj.enable = 0
else
let text = quickui#core#expand_text(text)
let obj.enable = 1
if strpart(text, 0, 1) == '~'
let text = strpart(text, 1)
let obj.enable = 0
endif
let pos = stridx(text, "\t")
let sep = ">"
if pos < 0
let obj.text = text
let obj.desc = ""
else
let obj.text = strpart(text, 0, pos)
let obj.desc = strpart(text, pos + 1)
let obj.desc = substitute(obj.desc, "\t", " ", "g")
endif
let obj.desc = (child == 0)? obj.desc : sep
let text = obj.text
let rest = ''
let start = 0
while 1
let pos = stridx(text, "&", start)
if pos < 0
let rest .= strpart(text, start)
break
end
let rest .= strpart(text, start, pos - start)
let key = strpart(text, pos + 1, 1)
let start = pos + 2
if key == '&'
let rest .= '&'
elseif key == '~'
let rest .= '~'
else
let obj.key_char = key
let obj.key_pos = strwidth(rest)
let rest .= key
endif
endwhile
let obj.text = rest
let obj.text_width = strwidth(obj.text)
let obj.desc_width = strwidth(obj.desc)
end
return obj
endfunc
"----------------------------------------------------------------------
" alignment
"----------------------------------------------------------------------
function! quickui#utils#context_align(item, left_size, right_size)
let obj = a:item
let middle = (a:right_size > 0)? 2 : 0
let size = a:left_size + a:right_size + middle
if obj.is_sep
let obj.content = repeat('-', size)
else
if obj.text_width < a:left_size
let delta = a:left_size - obj.text_width
let obj.text_left = obj.text . repeat(' ', delta)
else
let obj.text_left = obj.text
endif
if obj.desc_width < a:right_size
let delta = a:right_size - obj.desc_width
let obj.text_right = repeat(' ', delta) . obj.desc
else
let obj.text_right = obj.desc
endif
if a:right_size > 0
let obj.content = obj.text_left . ' ' . obj.text_right
else
let obj.content = obj.text_left
endif
endif
return obj
endfunc
"----------------------------------------------------------------------
" style: default
"----------------------------------------------------------------------
function! quickui#utils#highlight(style)
let style = (type(a:style) == v:t_number)? (''. a:style) : a:style
let style = tolower(style)
if style == '' || style == '0' || style == 'default' || style == 'Pmenu'
hi! link TVisionBG Pmenu
hi! link TVisionKey Keyword
hi! link TVisionOff Comment
hi! link TVisionSel PmenuSel
hi! link TVisionHelp Title
elseif style == 'borland'
endif
endfunc
"----------------------------------------------------------------------
" build map
"----------------------------------------------------------------------
let s:maps = {}
let s:maps["\<ESC>"] = 'ESC'
let s:maps["\<CR>"] = 'ENTER'
let s:maps["\<SPACE>"] = 'ENTER'
let s:maps["\<UP>"] = 'UP'
let s:maps["\<DOWN>"] = 'DOWN'
let s:maps["\<LEFT>"] = 'LEFT'
let s:maps["\<RIGHT>"] = 'RIGHT'
let s:maps["\<HOME>"] = 'HOME'
let s:maps["\<END>"] = 'END'
let s:maps["\<c-j>"] = 'DOWN'
let s:maps["\<c-k>"] = 'UP'
let s:maps["\<c-h>"] = 'LEFT'
let s:maps["\<c-l>"] = 'RIGHT'
let s:maps["\<c-n>"] = 'NEXT'
let s:maps["\<c-p>"] = 'PREV'
let s:maps["\<c-b>"] = 'PAGEUP'
let s:maps["\<c-f>"] = 'PAGEDOWN'
let s:maps["\<c-u>"] = 'HALFUP'
let s:maps["\<c-d>"] = 'HALFDOWN'
let s:maps["\<PageUp>"] = 'PAGEUP'
let s:maps["\<PageDown>"] = 'PAGEDOWN'
let s:maps["\<c-g>"] = 'NOHL'
let s:maps['j'] = 'DOWN'
let s:maps['k'] = 'UP'
let s:maps['h'] = 'LEFT'
let s:maps['l'] = 'RIGHT'
let s:maps['J'] = 'HALFDOWN'
let s:maps['K'] = 'HALFUP'
let s:maps['H'] = 'PAGEUP'
let s:maps['L'] = 'PAGEDOWN'
let s:maps["g"] = 'TOP'
let s:maps["G"] = 'BOTTOM'
let s:maps['q'] = 'ESC'
let s:maps['n'] = 'NEXT'
let s:maps['N'] = 'PREV'
function! quickui#utils#keymap()
return deepcopy(s:maps)
endfunc
"----------------------------------------------------------------------
" python simulate system() on window to prevent temporary window
"----------------------------------------------------------------------
function! s:python_system(cmd, version)
if has('nvim')
let hr = system(a:cmd)
elseif has('win32') || has('win64') || has('win95') || has('win16')
if a:version < 0 || (has('python3') == 0 && has('python2') == 0)
let hr = system(a:cmd)
let s:shell_error = v:shell_error
return hr
elseif a:version == 3
let pyx = 'py3 '
let python_eval = 'py3eval'
elseif a:version == 2
let pyx = 'py2 '
let python_eval = 'pyeval'
else
let pyx = 'pyx '
let python_eval = 'pyxeval'
endif
exec pyx . 'import subprocess, vim'
exec pyx . '__argv = {"args":vim.eval("a:cmd"), "shell":True}'
exec pyx . '__argv["stdout"] = subprocess.PIPE'
exec pyx . '__argv["stderr"] = subprocess.STDOUT'
exec pyx . '__pp = subprocess.Popen(**__argv)'
exec pyx . '__return_text = __pp.stdout.read()'
exec pyx . '__pp.stdout.close()'
exec pyx . '__return_code = __pp.wait()'
exec 'let l:hr = '. python_eval .'("__return_text")'
exec 'let l:pc = '. python_eval .'("__return_code")'
let s:shell_error = l:pc
return l:hr
else
let hr = system(a:cmd)
endif
let s:shell_error = v:shell_error
return hr
endfunc
"----------------------------------------------------------------------
" execute external program and return its output
"----------------------------------------------------------------------
function! quickui#utils#system(cmd)
let hr = s:python_system(a:cmd, get(g:, 'quickui_python', 0))
let g:quickui#utils#shell_error = s:shell_error
return hr
endfunc
"----------------------------------------------------------------------
" display a error msg
"----------------------------------------------------------------------
function! quickui#utils#errmsg(what)
redraw
echohl ErrorMsg
echom a:what
echohl None
endfunc
"----------------------------------------------------------------------
" safe print
"----------------------------------------------------------------------
function! quickui#utils#print(content, highlight, ...)
let saveshow = &showmode
set noshowmode
let wincols = &columns
let statusline = (&laststatus==1 && winnr('$')>1) || (&laststatus==2)
let reqspaces_lastline = (statusline || !&ruler) ? 12 : 29
let width = len(a:content)
let limit = wincols - reqspaces_lastline
let l:content = a:content
if width + 1 > limit
let l:content = strpart(l:content, 0, limit - 1)
let width = len(l:content)
endif
" prevent scrolling caused by multiple echo
let needredraw = (a:0 >= 1)? a:1 : 1
if needredraw != 0
redraw
endif
if a:highlight != 0
echohl Type
echo l:content
echohl NONE
else
echo l:content
endif
if saveshow != 0
set showmode
endif
endfunc
"----------------------------------------------------------------------
" max height
"----------------------------------------------------------------------
function! quickui#utils#max_height(percentage)
return (&lines) * a:percentage / 100
endfunc
"----------------------------------------------------------------------
" cursor movement
"----------------------------------------------------------------------
function! quickui#utils#movement(offset)
let height = winheight(0)
let winline = winline()
let curline = line('.')
let topline = curline - winline + 1
let topline = (topline < 1)? 1 : topline
let botline = topline + height - 1
let offset = 0
if type(a:offset) == v:t_number
let offset = a:offset
elseif type(a:offset) == v:t_string
if a:offset == 'PAGEUP'
let offset = -height
elseif a:offset == 'PAGEDOWN'
let offset = height
elseif a:offset == 'HALFUP' || a:offset == 'LEFT'
let offset = -(height / 2)
elseif a:offset == 'HALFDOWN' || a:offset == 'RIGHT'
let offset = height / 2
elseif a:offset == 'UP'
let offset = -1
elseif a:offset == 'DOWN'
let offset = 1
elseif a:offset == 'TOP'
exec "noautocmd normal gg"
return
elseif a:offset == 'BOTTOM'
exec "noautocmd normal G"
return
endif
endif
" echom "offset: ". offset
if offset > 0
exec "noautocmd normal ". offset . "\<C-E>"
elseif offset < 0
exec "noautocmd normal ". (-offset) . "\<C-Y>"
endif
endfunc
"----------------------------------------------------------------------
" cursor scroll
"----------------------------------------------------------------------
function! quickui#utils#scroll(winid, offset)
if type(a:offset) == v:t_number
let cmd = 'call quickui#utils#movement(' . a:offset . ')'
call quickui#core#win_execute(a:winid, cmd)
else
let cmd = 'call quickui#utils#movement("' . a:offset . '")'
call quickui#core#win_execute(a:winid, cmd)
endif
endfunc
"----------------------------------------------------------------------
" centerize
"----------------------------------------------------------------------
function! quickui#utils#center(winid, ...)
if g:quickui#core#has_nvim == 0
let pos = popup_getpos(a:winid)
else
let pos = {}
let pos.width = nvim_win_get_width(a:winid)
let pos.height = nvim_win_get_height(a:winid)
endif
let h = pos.height
let w = pos.width
let mode = (a:0 < 1)? 0 : (a:1)
let scale = (mode == 0)? 80 : 68
let limit1 = (&lines - 2) * scale / 100
let limit2 = (&lines - 2)
let opts = {}
if h + 4 < limit1
let opts.line = (limit1 - h) / 2
else
let opts.line = (limit2 - h) / 2
endif
let opts.col = (&columns - w) / 2
let opts.col = (opts.col < 1)? 1 : (opts.col)
let hr = quickui#core#screen_fit(opts.line, opts.col, w, h)
let opts.col = hr[1]
let opts.line = hr[0]
if g:quickui#core#has_nvim == 0
call popup_move(a:winid, opts)
else
let no = {'col': opts.col - 1, 'row': opts.line - 1}
let no.relative = 'editor'
call nvim_win_set_config(a:winid, no)
endif
endfunc
"----------------------------------------------------------------------
" show cursorline in textbox
"----------------------------------------------------------------------
function! quickui#utils#show_cursor(winid, row)
let height = winheight(0)
let winline = winline()
let curline = line('.')
let topline = curline - winline + 1
let topline = (topline < 1)? 1 : topline
let botline = topline + height - 1
let w:__quickui_line__ = get(w:, '__quickui_line__', -1)
if a:row >= topline && a:row <= botline
exec ":" . a:row
if w:__quickui_line__ != 1
if g:quickui#core#has_nvim == 0
call popup_setoptions(a:winid, {'cursorline': 1})
else
call quickui#core#win_execute(a:winid, 'setl cursorline')
if exists('+cursorlineopt')
call quickui#core#win_execute(a:winid, 'setl cursorlineopt=both')
endif
endif
endif
let w:__quickui_line__ = 1
else
if w:__quickui_line__ != 0
if g:quickui#core#has_nvim == 0
call popup_setoptions(a:winid, {'cursorline': 0})
else
call quickui#core#win_execute(a:winid, 'setl nocursorline')
endif
endif
let w:__quickui_line__ = 0
endif
endfunc
"----------------------------------------------------------------------
" update cursor line
"----------------------------------------------------------------------
function! quickui#utils#update_cursor(winid)
let bid = winbufnr(a:winid)
let row = getbufvar(bid, '__quickui_cursor__', -1)
let cmd = 'call quickui#utils#show_cursor('. a:winid .', '.row.')'
call quickui#core#win_execute(a:winid, cmd)
endfunc
"----------------------------------------------------------------------
" get window line
"----------------------------------------------------------------------
function! quickui#utils#get_cursor(winid)
let g:quickui#utils#__cursor_index__ = -1
let cmd = 'let g:quickui#utils#__cursor_index__ = line(".")'
noautocmd call quickui#core#win_execute(a:winid, cmd)
return g:quickui#utils#__cursor_index__
endfunc
"----------------------------------------------------------------------
" get topline in current window
"----------------------------------------------------------------------
function! quickui#utils#current_topline()
let height = winheight(0)
let winline = winline()
let curline = line('.')
let topline = curline - winline + 1
return topline
endfunc
"----------------------------------------------------------------------
" get first cursorline
"----------------------------------------------------------------------
function! quickui#utils#get_topline(winid)
let g:quickui#utils#__cursor_topline__ = -1
let cmd = 'let g:quickui#utils#__cursor_topline__ = '
let cmd = cmd . 'quickui#utils#current_topline()'
call quickui#core#win_execute(a:winid, cmd)
return g:quickui#utils#__cursor_topline__
endfunc
"----------------------------------------------------------------------
" make border
"----------------------------------------------------------------------
function! quickui#utils#make_border(width, height, border, title, ...)
let pattern = quickui#core#border_get(a:border)
let image = []
let w = a:width
let h = a:height
let text = pattern[0] . repeat(pattern[1], w) . pattern[2]
let image += [text]
let index = 0
while index < h
let text = pattern[3] . repeat(' ', w) . pattern[5]
let image += [text]
let index += 1
endwhile
let text = pattern[6] . repeat(pattern[7], w) . pattern[8]
let image += [text]
let button = (a:0 > 0)? (a:1) : 0
let align = (a:0 > 1)? (a:2) : ''
let text = image[0]
let title = quickui#core#string_fit(a:title, w)
if align == '' || align == 'l'
let text = quickui#core#string_compose(text, 1, title)
elseif align == 'm'
let left = (w + 2 - len(title)) / 2
let text = quickui#core#string_compose(text, left, title)
elseif align == 'r'
let left = w + 2 - len(title) - 1
let text = quickui#core#string_compose(text, left, title)
endif
if button != 0
let text = quickui#core#string_compose(text, w + 1, 'X')
endif
let image[0] = text
return image
endfunc
"----------------------------------------------------------------------
" search or jump
"----------------------------------------------------------------------
function! quickui#utils#search_or_jump(winid, cmd)
if a:cmd == '/' || a:cmd == '?'
let prompt = (a:cmd == '/')? '/' : '?'
" let prompt = (a:cmd == '/')? '(search): ' : '(search backwards): '
let t = quickui#core#input(prompt, '')
if t != '' && t != "\<c-c>"
try
silent call quickui#core#win_execute(a:winid, a:cmd . t)
catch /^Vim\%((\a\+)\)\=:E486:/
call quickui#utils#errmsg('E486: Pattern not find: '. t)
endtry
silent! call quickui#core#win_execute(a:winid, 'nohl')
call setwinvar(a:winid, '__quickui_search_cmd', a:cmd)
call setwinvar(a:winid, '__quickui_search_key', t)
endif
elseif a:cmd == ':'
let prompt = ':'
" let prompt = '(goto): '
let t = quickui#core#input(prompt, '')
if t != ''
call quickui#core#win_execute(a:winid, ':' . t)
endif
endif
endfunc
"----------------------------------------------------------------------
" search next
"----------------------------------------------------------------------
function! quickui#utils#search_next(winid, cmd)
let prev_cmd = getwinvar(a:winid, '__quickui_search_cmd', '')
let prev_key = getwinvar(a:winid, '__quickui_search_key', '')
if prev_key != ''
if a:cmd ==# 'n' || a:cmd == 'NEXT'
let cmd = (prev_cmd == '/')? '/' : '?'
else
let cmd = (prev_cmd == '/')? '?' : '/'
endif
try
silent call quickui#core#win_execute(a:winid, cmd . prev_key)
catch /^Vim\%((\a\+)\)\=:E486:/
endtry
noautocmd call quickui#core#win_execute(a:winid, 'nohl')
endif
let cmds = ['exec line(".")']
let cmds += ['normal! 0']
silent call quickui#core#win_execute(a:winid, cmds)
endfunc
"----------------------------------------------------------------------
" size can be in '24' or '24%' or '0.25'
"----------------------------------------------------------------------
function! quickui#utils#read_size(text, maxsize)
if type(a:text) == v:t_number
return a:text
elseif type(a:text) == v:t_string
let text = trim(a:text)
if text =~ '%$'
let text = strpart(text, 0, len(text) - 1)
let ratio = str2nr(text)
let num = (a:maxsize) * ratio / 100
return (num < a:maxsize)? num : a:maxsize
else
let fsize = str2float(a:text)
if fsize <= 1.0
return float2nr(fsize * a:maxsize)
endif
let size = float2nr(fsize)
return (size > a:maxsize)? a:maxsize : size
endif
elseif type(a:text) == v:t_float
let fsize = a:text
if fsize <= 1.0
return float2nr(fsize * a:maxsize)
endif
let size = float2nr(fsize)
return (size > a:maxsize)? a:maxsize : size
endif
endfunc
"----------------------------------------------------------------------
" get default tools width
"----------------------------------------------------------------------
function! quickui#utils#tools_width()
let width = get(g:, 'quickui_tools_width', '60%')
let size = quickui#utils#read_size(width, &columns)
let minimal = (60 < &columns)? 60 : &columns
let size = (size < minimal)? minimal : size
return (size > &columns)? &columns : size
endfunc
"----------------------------------------------------------------------
" read from register or evaluation
"----------------------------------------------------------------------
function! quickui#utils#read_eval(...)
let opts = (a:0 == 0)? {} : (a:1)
try
let code = getchar()
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
let ch = (type(code) == v:t_number)? nr2char(code) : code
if ch == "\<c-c>"
return ''
elseif ch == "\<esc>" || ch == "\<cr>"
return ''
elseif ch == "="
let e = input('=')
if e == ''
return ''
endif
return eval(e)
elseif ch == "\<c-w>"
let x = expand('<cword>')
return x
elseif len(ch) == 1
let x = eval('@' . ch)
return x
endif
return ''
endfunc
"----------------------------------------------------------------------
" normalize textlist
"----------------------------------------------------------------------
function! quickui#utils#text_list_normalize(textlist)
if type(a:textlist) == v:t_list
let textlist = a:textlist
else
let textlist = split('' . a:textlist, '\n', 1)
endif
let out = []
for text in textlist
let text = substitute(text, '[\r\n\t]', ' ', 'g')
let out += [text]
endfor
return out
endfunc
"----------------------------------------------------------------------
" getchar
"----------------------------------------------------------------------
function! quickui#utils#getchar(wait)
try
if a:wait != 0
let code = getchar()
else
let code = getchar(0)
endif
catch /^Vim:Interrupt$/
let code = "\<C-C>"
endtry
if type(code) == v:t_number && code == 0
try
exec 'sleep 15m'
continue
catch /^Vim:Interrupt$/
let code = "\<c-c>"
endtry
endif
let ch = (type(code) == v:t_number)? nr2char(code) : code
return ch
endfunc
"----------------------------------------------------------------------
" switch buffer
"----------------------------------------------------------------------
function! quickui#utils#switch(filename, opts)
let switch = get(g:, 'quickui_switch_mode', &switchbuf)
let switch = get(a:opts, 'switch', switch)
let method = split(switch, ',')
let goto = get(a:opts, 'goto', -1)
let ft = get(a:opts, 'ft', '')
let cmds = get(a:opts, 'command', [])
if type(a:filename) == type('')
let filename = expand(a:filename)
if filereadable(filename) == 0
if get(a:opts, 'exist', 0) != 0
echohl ErrorMsg
echom "E484: Can't open file " . (a:filename)
echohl None
return 0
endif
endif
let bid = bufnr(filename)
else
let bid = a:filename
if bid < 0
return 0
endif
endif
if index(method, 'useopen') >= 0
for wid in range(winnr('$'))
let b = winbufnr(wid + 1)
if b == bid
silent exec ''. (wid + 1) . 'wincmd w'
if goto > 0
silent exec ':' . goto
endif
for cmd in cmds
exec cmd
endfor
return 1
endif
endfor
endif
if index(method, 'usetab') >= 0
for tid in range(tabpagenr('$'))
let buflist = tabpagebuflist(tid + 1)
for wid in range(len(buflist))
if bid == buflist[wid]
silent exec 'tabn ' . (tid + 1)
silent exec '' . (wid + 1) . 'wincmd w'
if goto > 0
silent exec ':' . goto
endif
for cmd in cmds
exec cmd
endfor
return 1
endif
endfor
endfor
endif
if index(method, 'newtab') >= 0
silent exec 'tab split'
elseif index(method, 'uselast') >= 0
silent exec 'wincmd p'
elseif index(method, 'edit') >= 0
silent exec ''
elseif index(method, 'drop') >= 0
else
if &buftype != ''
silent exec 'wincmd p'
endif
for i in range(winnr('$'))
if &buftype == ''
break
endif
silent exec 'wincmd w'
endfor
let mods = get(a:opts, 'mods', '')
if index(method, 'auto') >= 0
if winwidth(0) >= 160
exec mods . ' vsplit'
else
exec mods . ' split'
endif
elseif index(method, 'split') >= 0
exec mods . ' split'
elseif index(method, 'vsplit') >= 0
exec mods . ' vsplit'
endif
endif
try
let force = ((get(a:opts, 'force', 0) != 0)? '!' : '')
if bid >= 0
exec 'b' . force . ' ' . bid
else
exec 'edit' . force . ' ' . fnameescape(expand(a:filename))
endif
catch /^Vim\%((\a\+)\)\=:E37:/
echohl ErrorMsg
echo 'E37: No write since last change (set force=1 to override)'
echohl None
return 0
endtry
if goto > 0
exec ':' . goto
endif
if ft != ''
exec 'setlocal ft=' . fnameescape(ft)
endif
for cmd in cmds
exec cmd
endfor
return 1
endfunc
"----------------------------------------------------------------------
" returns 1 if filetype matches pattern, otherwise returns 0
"----------------------------------------------------------------------
function! quickui#utils#match_ft(filetype, pattern)
let pattern = quickui#core#string_strip(a:pattern)
let ft = a:filetype
if pattern == ''
return 0
elseif pattern =~ '^/'
let pattern = strpart(pattern, 1)
if match(ft, pattern) >= 0
return 1
endif
elseif pattern =~ '^!'
let pattern = strpart(pattern, 1)
if match(ft, pattern) < 0
return 1
endif
endif
let blacklist = []
let whitelist = []
for check in split(pattern, ',')
if pattern[0] == '-'
let blacklist += [check]
else
let whitelist += [check]
endif
endfor
if index(blacklist, '-' . ft) >= 0
return 0
endif
if empty(whitelist) || index(whitelist, ft) >= 0
return 1
endif
return 0
endfunc
"----------------------------------------------------------------------
" format table
"----------------------------------------------------------------------
function! quickui#utils#tabulify(rows)
let content = []
let rows = []
let nrows = len(a:rows)
let ncols = 0
for row in a:rows
if len(row) > ncols
let ncols = len(row)
endif
endfor
if nrows == 0 || ncols == 0
return content
endif
let sizes = repeat([0], ncols)
let index = range(ncols)
for row in a:rows
let newrow = deepcopy(row)
if len(newrow) < ncols
let newrow += repeat([''], ncols - len(newrow))
endif
for i in index
let size = strwidth(newrow[i])
let sizes[i] = (sizes[i] < size)? size : sizes[i]
endfor
let rows += [newrow]
endfor
for row in rows
let ni = []
for i in index
let x = row[i]
let size = strwidth(x)
if size < sizes[i]
let x = x . repeat(' ', sizes[i] - size)
endif
let ni += [x]
endfor
let content += [ni]
endfor
return content
endfunc
"----------------------------------------------------------------------
" print table
"----------------------------------------------------------------------
function! quickui#utils#print_table(rows, highmap)
let content = quickui#utils#tabulify(a:rows)
let index = 0
for line in content
let col = 0
echon (index == 0)? " " : "\n "
for cell in line
let key = index . ',' . col
if !has_key(a:highmap, key)
echohl None
else
exec 'echohl ' . a:highmap[key]
endif
echon cell . ' '
let col += 1
endfor
let index += 1
endfor
echohl None
endfunc

View File

@ -0,0 +1,757 @@
"======================================================================
"
" window.vim -
"
" Created by skywind on 2021/12/08
" Last Modified: 2021/12/08 23:45
"
"======================================================================
" vim: set ts=4 sw=4 tw=78 noet :
"----------------------------------------------------------------------
" window class
"----------------------------------------------------------------------
let s:window = {}
let s:window.w = 1 " window width
let s:window.h = 1 " window height
let s:window.x = 1 " column starting from 0
let s:window.y = 1 " row starting from 0
let s:window.z = 40 " priority
let s:window.winid = -1 " window id
let s:window.dirty = 0 " need update buffer ?
let s:window.text = [] " text lines
let s:window.bid = -1 " allocated buffer id
let s:window.hide = 0 " visibility
let s:window.mode = 0 " mode: 0/created, 1/closed
let s:window.opts = {} " creation options
let s:window.info = {} " init environment
let s:window.quit = 0 " closed by button ? (vim only)
"----------------------------------------------------------------------
" internal
"----------------------------------------------------------------------
let s:has_nvim = g:quickui#core#has_nvim
let s:has_nvim_060 = g:quickui#core#has_nvim_060
"----------------------------------------------------------------------
" prepare opts
"----------------------------------------------------------------------
function! s:window.__prepare_opts(textlist, opts)
let opts = deepcopy(a:opts)
let opts.x = get(a:opts, 'x', 1)
let opts.y = get(a:opts, 'y', 1)
let opts.z = get(a:opts, 'z', 40)
let opts.w = get(a:opts, 'w', 1)
let opts.h = get(a:opts, 'h', -1)
let opts.hide = get(a:opts, 'hide', 0)
let opts.wrap = get(a:opts, 'wrap', 0)
let opts.color = get(a:opts, 'color', 'QuickBG')
let opts.border = get(a:opts, 'border', 0)
let self.opts = opts
let self.bid = quickui#core#buffer_alloc()
let self.dirty = 1
let self.x = opts.x
let self.y = opts.y
let self.z = opts.z
let self.w = (opts.w < 1)? 1 : (opts.w)
let self.h = (opts.h < 1)? 1 : (opts.h)
let self.hide = opts.hide
let self.mode = 0
if has_key(a:opts, 'padding')
let self.opts.padding = a:opts.padding
else
let self.opts.padding = [0,0,0,0]
endif
let pad = self.opts.padding
let info = self.info
let info.tw = self.w + pad[1] + pad[3]
let info.th = self.h + pad[0] + pad[2]
let sum_pad = pad[0] + pad[1] + pad[2] + pad[3]
let info.has_padding = (sum_pad > 0)? 1 : 0
let border = quickui#core#border_auto(self.opts.border)
let info.has_border = (self.opts.border > 0)? 1 : 0
if info.has_border != 0
let info.tw += 2
let info.th += 2
endif
" echom info
call self.set_text(a:textlist)
if opts.h < 0
let opts.h = len(self.text)
endif
let cmd = []
if has_key(opts, 'tabstop')
let cmd += ['setl tabstop=' . get(opts, 'tabstop', 4)]
endif
if has_key(opts, 'list')
let cmd += [(opts.list)? 'setl list' : 'setl nolist']
else
let cmd += ['setl nolist']
endif
if get(opts, 'number', 0) != 0
let cmd += ['setl number']
else
let cmd += ['setl nonumber']
endif
let cmd += ['setl scrolloff=0']
let cmd += ['setl signcolumn=no']
if has_key(opts, 'syntax')
let cmd += ['set ft=' . fnameescape(opts.syntax)]
endif
if has_key(opts, 'cursorline')
let need = (opts.cursorline)? 'cursorline' : 'nocursorlin'
let cmd += ['setl ' . need]
if exists('+cursorlineopt')
let cmd += ['setl cursorlineopt=both']
endif
else
let cmd += ['setl nocursorline']
endif
let cmd += ['setl nocursorcolumn nospell']
let cmd += [opts.wrap? 'setl wrap' : 'setl nowrap']
if has_key(opts, 'command')
let command = opts.command
if type(command) == type([])
let cmd += command
else
let cmd += [''. command]
endif
endif
let info.cmd = cmd
let info.pending_cmd = []
let info.border_winid = -1
let info.border_bid = -1
endfunc
"----------------------------------------------------------------------
" win filter
"----------------------------------------------------------------------
function! s:popup_filter(winid, key)
let local = quickui#core#popup_local(a:winid)
let hwnd = local.window_hwnd
endfunc
"----------------------------------------------------------------------
" exited
"----------------------------------------------------------------------
function! s:popup_exit(winid, code)
let local = quickui#core#popup_local(a:winid)
let hwnd = local.window_hwnd
call quickui#core#popup_clear(a:winid)
let hwnd.quit = 1
let hwnd.winid = -1
endfunc
"----------------------------------------------------------------------
" create window in vim
"----------------------------------------------------------------------
function! s:window.__vim_create()
let opts = {"hidden":1, "pos": 'topleft'}
let opts.hidden = 1
let opts.wrap = self.opts.wrap
let opts.minwidth = self.w
let opts.maxwidth = self.w
let opts.minheight = self.h
let opts.maxheight = self.h
let opts.col = self.x + 1
let opts.line = self.y + 1
let opts.mapping = 0
let opts.fixed = (opts.wrap == 0)? 1 : 0
let opts.cursorline = get(self.opts, 'cursorline', 0)
let opts.drag = get(self.opts, 'drag', 0)
let opts.scrollbar = 0
let opts.zindex = self.z + 1
if get(self.opts, 'button', 0) != 0
let opts.close = 'button'
endif
let self.winid = popup_create(self.bid, opts)
let winid = self.winid
let local = quickui#core#popup_local(winid)
let local.window_hwnd = self
let init = []
let init += ['setlocal nonumber signcolumn=no scrolloff=0']
call quickui#core#win_execute(winid, init, 1)
let opts = {}
let opts.filter = function('s:popup_filter')
let opts.callback = function('s:popup_exit')
let opts.highlight = self.opts.color
let border = quickui#core#border_auto(self.opts.border)
if self.info.has_border
let opts.borderchars = border
let opts.border = [1,1,1,1,1,1,1,1,1]
let bc = get(self.opts, 'bordercolor', 'QuickBorder')
let opts.borderhighlight = [bc, bc, bc, bc]
if has_key(self.opts, 'title')
let opts.title = self.opts.title
endif
endif
if has_key(self.opts, 'padding')
let opts.padding = self.opts.padding
endif
call setwinvar(winid, '&wincolor', self.opts.color)
call popup_setoptions(winid, opts)
call quickui#core#win_execute(winid, self.info.cmd)
let pc = self.info.pending_cmd
if len(pc) > 0
call quickui#core#win_execute(winid, pc)
let self.info.pending_cmd = []
endif
let self.mode = 1
if get(self.opts, 'center', 0) != 0
call self.center()
endif
if self.hide == 0
call popup_show(winid)
endif
endfunc
"----------------------------------------------------------------------
" create window in nvim
"----------------------------------------------------------------------
function! s:window.__nvim_create()
let opts = {'focusable':0, 'style':'minimal', 'relative':'editor'}
let opts.row = self.y
let opts.col = self.x
let opts.width = self.w
let opts.height = self.h
let opts.focusable = get(self.opts, 'focusable', 0)
if s:has_nvim_060
let opts.noautocmd = 1
let opts.zindex = self.z + 1
endif
let info = self.info
let info.nvim_opts = opts
let info.sim_border = 0
let info.off_x = 0
let info.off_y = 0
let pad = self.opts.padding
if info.has_border
let info.sim_border = 1
let info.off_x = 1
let info.off_y = 1
if info.has_padding
let info.sim_border = 1
let info.off_x += pad[3]
let info.off_y += pad[0]
endif
endif
if info.has_border
let tw = info.tw
let th = info.th
let opts.col += info.off_x
let opts.row += info.off_y
let t = get(self.opts, 'title', '')
let b = get(self.opts, 'button', 0)
let border = self.opts.border
let back = quickui#utils#make_border(tw - 2, th - 2, border, t, b)
let info.border_bid = quickui#core#buffer_alloc()
call quickui#core#buffer_update(info.border_bid, back)
let op = {'relative':'editor', 'focusable':0, 'style':'minimal'}
let op.focusable = get(self.opts, 'focusable', 0)
let op.width = tw
let op.height = th
let op.col = self.x
let op.row = self.y
if s:has_nvim_060
let op.noautocmd = 1
let op.zindex = self.z
endif
let info.border_opts = op
let init = []
let init += ['setl tabstop=' . get(self.opts, 'tabstop', 4)]
let init += ['setl signcolumn=no scrolloff=0 nowrap nonumber']
let init += ['setl nocursorline nolist']
if exists('+cursorlineopt')
let init += ['setl cursorlineopt=both']
endif
let info.border_init = init
endif
let self.mode = 1
if get(self.opts, 'center', 0) != 0
call self.center()
endif
if self.hide == 0
call self.__nvim_show()
endif
endfunc
"----------------------------------------------------------------------
" nvim - show window
"----------------------------------------------------------------------
function! s:window.__nvim_show()
if self.mode == 0
return
elseif self.winid >= 0
return
endif
call self.move(self.x, self.y)
let info = self.info
let winid = nvim_open_win(self.bid, 0, info.nvim_opts)
let self.winid = winid
let color = self.opts.color
call quickui#core#win_execute(winid, info.cmd)
if len(info.pending_cmd) > 0
call quickui#core#win_execute(winid, info.pending_cmd)
let info.pending_cmd = []
endif
call nvim_win_set_option(self.winid, 'winhl', 'Normal:'. color)
if info.has_border
let bwid = nvim_open_win(info.border_bid, 0, info.border_opts)
let info.border_winid = bwid
call quickui#core#win_execute(bwid, info.border_init)
call nvim_win_set_option(bwid, 'winhl', 'Normal:'. color)
endif
let self.hide = 0
endfunc
"----------------------------------------------------------------------
" nvim - hide window
"----------------------------------------------------------------------
function! s:window.__nvim_hide()
if self.mode == 0
return
elseif self.winid < 0
return
endif
let info = self.info
if info.border_winid >= 0
call nvim_win_close(info.border_winid, 1)
let info.border_winid = -1
endif
if self.winid >= 0
call nvim_win_close(self.winid, 1)
let self.winid = -1
endif
let self.hide = 1
endfunc
"----------------------------------------------------------------------
" open window
"----------------------------------------------------------------------
function! s:window.open(textlist, opts)
call self.close()
call self.__prepare_opts(a:textlist, a:opts)
if s:has_nvim == 0
call self.__vim_create()
else
call self.__nvim_create()
endif
let self.mode = 1
endfunc
"----------------------------------------------------------------------
" close window
"----------------------------------------------------------------------
function! s:window.close()
if self.winid >= 0
if s:has_nvim == 0
call popup_close(self.winid)
else
call nvim_win_close(self.winid, 1)
if self.info.border_winid >= 0
call nvim_win_close(self.info.border_winid, 1)
let self.info.border_winid = -1
endif
endif
endif
let self.winid = -1
if self.bid >= 0
call quickui#core#buffer_free(self.bid)
let self.bid = -1
endif
if has_key(self.info, 'border_bid')
if self.info.border_bid >= 0
call quickui#core#buffer_free(self.info.border_bid)
let self.info.border_bid = -1
endif
endif
let self.hide = 0
let self.mode = 0
endfunc
"----------------------------------------------------------------------
" show the window
"----------------------------------------------------------------------
function! s:window.show(show)
if self.mode == 0
return
elseif s:has_nvim == 0
if a:show == 0
if self.winid >= 0
call popup_hide(self.winid)
endif
else
if self.winid >= 0
call popup_show(self.winid)
endif
endif
else
if a:show == 0
call self.__nvim_hide()
else
call self.__nvim_show()
endif
endif
let self.hide = (a:show == 0)? 1 : 0
endfunc
"----------------------------------------------------------------------
" move window
"----------------------------------------------------------------------
function! s:window.__move(x, y)
let self.x = a:x
let self.y = a:y
if self.mode == 0
return
elseif s:has_nvim == 0
if self.winid >= 0
let opts = {}
let opts.col = self.x + 1
let opts.line = self.y + 1
call popup_move(self.winid, opts)
endif
else
let info = self.info
let opts = info.nvim_opts
let opts.col = self.x + info.off_x
let opts.row = self.y + info.off_y
if info.has_border != 0
let opts = info.border_opts
let opts.col = self.x
let opts.row = self.y
endif
if self.winid >= 0
let op = {'relative':'editor'}
let op.col = info.nvim_opts.col
let op.row = info.nvim_opts.row
call nvim_win_set_config(self.winid, op)
endif
if info.has_border != 0
if info.border_winid >= 0
let op = {'relative':'editor'}
let op.col = info.border_opts.col
let op.row = info.border_opts.row
call nvim_win_set_config(info.border_winid, op)
endif
endif
endif
endfunc
"----------------------------------------------------------------------
" actual move
"----------------------------------------------------------------------
function! s:window.move(x, y)
let x = a:x
let y = a:y
let w = self.info.tw
let h = self.info.th
let sw = &columns
let sh = &lines
let x = (x + w > sw)? (sw - w) : x
let y = (y + h > sh)? (sh - h) : y
let x = (x < 0)? 0 : x
let y = (y < 0)? 0 : y
" unsilent echom ['move', x, a:x, self.opts.x]
call self.__move(x, y)
endfunc
"----------------------------------------------------------------------
" center window
"----------------------------------------------------------------------
function! s:window.center(...)
let w = self.w
let h = self.h
let style = (a:0 < 1)? 0 : (a:1)
if self.mode != 0
let w = self.info.tw
let h = self.info.th
endif
let x = (&columns - w) / 2
if style == 0
let height = &lines - &cmdheight - 1
let middle = height * 38 / 100
let y = middle - (h + 1) / 2
let y = (y < 0)? 0 : y
else
let y = (&lines - h) / 2
let limit1 = (&lines - 2) * 80 / 100
let limit2 = (&lines - 2)
if h + 8 < limit1
let y = (limit1 - h) / 2
else
let y = (limit2 - h) / 2
endif
endif
call self.move(x, y)
endfunc
"----------------------------------------------------------------------
" resize
"----------------------------------------------------------------------
function! s:window.resize(w, h)
let self.w = a:w
let self.h = a:h
let info = self.info
if self.mode == 0
let info.tw = self.w
let info.th = self.h
return
endif
let pad = self.opts.padding
let info.tw = self.w + pad[1] + pad[3]
let info.th = self.h + pad[0] + pad[2]
let info.tw += (info.has_border? 2 : 0)
let info.th += (info.has_border? 2 : 0)
if self.winid < 0
return
endif
if s:has_nvim == 0
let opts = {}
let opts.minwidth = self.w
let opts.maxwidth = self.w
let opts.minheight = self.h
let opts.maxheight = self.h
call popup_move(self.winid, opts)
else
let opts = info.nvim_opts
let opts.width = self.w
let opts.height = self.h
if info.has_border
let opts = info.border_opts
let opts.width = info.tw
let opts.height = info.th
let t = get(self.opts, 'title', '')
let b = self.opts.border
let tw = info.tw
let th = info.th
let btn = get(self.opts, 'button', 0)
let back = quickui#utils#make_border(tw - 2, th - 2, b, t, btn)
call quickui#core#buffer_update(info.border_bid, back)
endif
if self.winid >= 0
let op = {'width':self.w, 'height':self.h}
call nvim_win_set_config(self.winid, op)
if info.has_border
if info.border_winid >= 0
let op = {'width':info.tw, 'height':info.th}
call nvim_win_set_config(info.border_winid, op)
endif
endif
endif
endif
endfunc
"----------------------------------------------------------------------
" execute commands
"----------------------------------------------------------------------
function! s:window.execute(cmdlist)
if type(a:cmdlist) == v:t_string
let cmd = split(a:cmdlist, '\n')
else
let cmd = a:cmdlist
endif
let winid = self.winid
if winid >= 0
let pc = self.info.pending_cmd
if len(pc) > 0
call quickui#core#win_execute(winid, pc)
let self.info.pending_cmd = []
endif
if len(cmd) > 0
call quickui#core#win_execute(winid, cmd)
endif
else
if !has_key(self.info, 'pending_cmd')
let self.info.pending_cmd = cmd
else
let self.info.pending_cmd += cmd
endif
endif
endfunc
"----------------------------------------------------------------------
" update text in buffer
"----------------------------------------------------------------------
function! s:window.update()
if self.bid >= 0
call quickui#core#buffer_update(self.bid, self.text)
endif
endfunc
"----------------------------------------------------------------------
" set content
"----------------------------------------------------------------------
function! s:window.set_text(textlist)
if type(a:textlist) == v:t_list
let textlist = deepcopy(a:textlist)
else
let textlist = split(a:textlist, '\n', 1)
endif
let self.text = textlist
call self.update()
endfunc
"----------------------------------------------------------------------
" set line
"----------------------------------------------------------------------
function! s:window.set_line(index, text, ...)
let require = a:index + 1
let refresh = (a:0 < 1)? 1 : (a:1)
let index = a:index
let update = 0
if index < 0
return
elseif len(self.text) < require
let self.text += repeat([''], require - len(self.text))
let update = 1
endif
let self.text[a:index] = a:text
if update != 0
call self.update()
elseif refresh != 0
let bid = self.bid
if bid >= 0
call setbufvar(bid, '&modifiable', 1)
call setbufline(bid, index + 1, [a:text])
call setbufvar(bid, '&modified', 0)
endif
endif
endfunc
"----------------------------------------------------------------------
" get line
"----------------------------------------------------------------------
function! s:window.get_line(index)
if a:index >= len(self.text)
return ''
endif
return self.text[a:index]
endfunc
"----------------------------------------------------------------------
" syntax begin
"----------------------------------------------------------------------
function! s:window.syntax_begin(...)
let info = self.info
let info.syntax_cmd = ['syn clear']
let info.syntax_mod = (a:0 < 1)? 1 : (a:1)
endfunc
"----------------------------------------------------------------------
" flush commands
"----------------------------------------------------------------------
function! s:window.syntax_end()
let info = self.info
if has_key(info, 'syntax_cmd') != 0
if len(info.syntax_cmd) > 0
call self.execute(info.syntax_cmd)
let info.syntax_cmd = []
endif
endif
endfunc
"----------------------------------------------------------------------
" calculate region
"----------------------------------------------------------------------
function! s:window.syntax_region(color, x1, y1, x2, y2)
let info = self.info
if a:y1 == a:y2 && a:x1 >= a:x2
return
elseif has_key(info, 'syntax_cmd') != 0
let x1 = a:x1 + 1
let y1 = a:y1 + 1
let x2 = a:x2 + 1
let y2 = a:y2 + 1
let cc = a:color
let mm = info.syntax_mod
let cmd = quickui#core#high_region(cc, y1, x1, y2, x2, mm)
let info.syntax_cmd += [cmd]
" echom cmd
endif
endfunc
"----------------------------------------------------------------------
" click window
"----------------------------------------------------------------------
function! s:window.mouse_click()
let winid = self.winid
let retval = {'x':-1, 'y':-1}
if g:quickui#core#has_nvim == 0
let pos = getmousepos()
if pos.winid != winid
return retval
endif
if self.info.has_border == 0
let retval.x = pos.column - 1
let retval.y = pos.line - 1
else
let retval.x = pos.column - 2
let retval.y = pos.line - 2
endif
else
if v:mouse_winid != winid
return retval
endif
if self.info.has_border == 0
let retval.x = v:mouse_col - 1
let retval.y = v:mouse_lnum - 1
else
let retval.x = v:mouse_col - 2
let retval.y = v:mouse_lnum - 2
endif
endif
return retval
endfunc
"----------------------------------------------------------------------
" refresh redraw
"----------------------------------------------------------------------
function! s:window.refresh()
let winid = self.winid
if g:quickui#core#has_nvim == 0
if winid >= 0
call popup_setoptions(winid, {})
endif
else
endif
redraw
endfunc
"----------------------------------------------------------------------
" constructor
"----------------------------------------------------------------------
function! quickui#window#new()
let obj = deepcopy(s:window)
return obj
endfunc

View File

@ -0,0 +1,19 @@
hi! QuickDefaultBackground ctermfg=0 ctermbg=7 guifg=black guibg=#c0c0c0
hi! QuickDefaultSel cterm=bold ctermfg=0 ctermbg=2 gui=bold guibg=brown guifg=#c0c0c0
hi! QuickDefaultKey term=bold ctermfg=9 gui=bold guifg=#f92772
hi! QuickDefaultDisable ctermfg=8 guifg=#75715e
hi! QuickDefaultHelp ctermfg=8 guifg=#959173
hi! QuickDefaultBorder ctermfg=0 ctermbg=7 guifg=black guibg=#c0c0c0
hi! QuickDefaultTermBorder ctermfg=0 ctermbg=7 guifg=black guibg=#c0c0c0
if &background == 'dark'
hi! QuickDefaultPreview ctermbg=237 guibg=#4c4846
else
hi! QuickDefaultPreview ctermbg=12 guibg=#dddddd
endif
hi! QuickDefaultInput ctermfg=7 ctermbg=4 guifg=#e4e4e4 guibg=#0000a0
hi! QuickDefaultCursor ctermfg=4 ctermbg=7 guifg=#0000a0 guibg=#e4e4e4
hi! QuickDefaultVisual ctermfg=4 ctermbg=15 guifg=#0000a0 guibg=#f4f4f4

View File

@ -0,0 +1,19 @@
hi! QuickDefaultBackground ctermfg=0 ctermbg=7 guifg=black guibg=#c0c0c0
hi! QuickDefaultSel cterm=bold ctermfg=0 ctermbg=2 gui=bold guibg=brown guifg=#c0c0c0
hi! QuickDefaultKey term=bold ctermfg=1 gui=bold guifg=#f92772
hi! QuickDefaultDisable ctermfg=6 guifg=#75715e
hi! QuickDefaultHelp ctermfg=6 guifg=#959173
hi! QuickDefaultBorder ctermfg=0 ctermbg=7 guifg=black guibg=#c0c0c0
hi! QuickDefaultTermBorder ctermfg=0 ctermbg=7 guifg=black guibg=#c0c0c0
if &background == 'dark'
hi! QuickDefaultPreview ctermbg=7 guibg=#4c4846
else
hi! QuickDefaultPreview ctermbg=4 guibg=#dddddd
endif
hi! QuickDefaultInput ctermfg=7 ctermbg=4 guifg=#e4e4e4 guibg=#0000a0
hi! QuickDefaultCursor ctermfg=4 ctermbg=7 guifg=#0000a0 guibg=#e4e4e4
hi! QuickDefaultVisual ctermfg=4 ctermbg=6 guifg=#0000a0 guibg=#f4f4f4

View File

@ -0,0 +1,19 @@
hi! QuickDefaultBackground ctermfg=187 ctermbg=239 guifg=#ebdbb2 guibg=#504945
hi! QuickDefaultSel cterm=bold ctermfg=239 ctermbg=108 gui=bold guifg=#504945 guibg=#83a598
hi! QuickDefaultKey term=bold ctermfg=208 guifg=#fd9720
hi! QuickDefaultDisable ctermfg=245 guifg=#928374
hi! QuickDefaultHelp ctermfg=109 guifg=#83a598
hi! QuickDefaultBorder ctermfg=187 ctermbg=239 guifg=#ebdbb2 guibg=#504945
hi! QuickDefaultTermBorder ctermfg=187 ctermbg=239 guifg=#ebdbb2 guibg=#504945
if &background == 'dark'
hi! QuickDefaultPreview ctermbg=237 guibg=#4c4846
else
hi! QuickDefaultPreview ctermbg=12 guibg=#dddddd
endif
hi! QuickDefaultInput ctermfg=233 ctermbg=235 guifg=#ebdbb2 guibg=#282828
hi! QuickDefaultCursor ctermfg=235 ctermbg=233 guifg=#282828 guibg=#ebdbb2
hi! QuickDefaultVisual ctermfg=241 ctermbg=233 guifg=#665c54 guibg=#ebdbb2

View File

@ -0,0 +1,19 @@
hi! QuickDefaultBackground ctermfg=251 ctermbg=236 guifg=#c6c6c6 guibg=#303030
hi! QuickDefaultSel ctermfg=236 ctermbg=251 guifg=#303030 guibg=#c6c6c6
hi! QuickDefaultKey term=bold ctermfg=179 gui=bold guifg=#d7af5f
hi! QuickDefaultDisable ctermfg=11 guifg=#808080
hi! QuickDefaultHelp ctermfg=7 ctermbg=8 guifg=#585858 guibg=#1c1c1c
hi! QuickDefaultBorder ctermfg=66 ctermbg=236 guifg=#5f8787 guibg=#303030
hi! QuickDefaultTermBorder ctermfg=66 ctermbg=236 guifg=#5f8787 guibg=#303030
if &background == 'dark'
hi! QuickDefaultPreview ctermbg=237 guibg=#4c4846
else
hi! QuickDefaultPreview ctermbg=12 guibg=#dddddd
endif
hi! QuickDefaultInput ctermfg=252 ctermbg=234 guifg=#d0d0d0 guibg=#1c1c1c
hi! QuickDefaultCursor ctermfg=234 ctermbg=252 guifg=#1c1c1c guibg=#d0d0d0
hi! QuickDefaultVisual ctermfg=8 ctermbg=255 guifg=#000000 guibg=#8787af

View File

@ -0,0 +1,32 @@
hi! QuickDefaultBackground ctermfg=238 ctermbg=252 guifg=#444444 guibg=#d0d0d0
hi! QuickDefaultSel ctermfg=252 ctermbg=238 guifg=#d0d0d0 guibg=#444444
hi! QuickDefaultKey term=bold ctermfg=162 gui=bold guifg=#d70087
hi! QuickDefaultDisable term=bold ctermfg=1 guifg=#878787
" hi! QuickDefaultHelp ctermfg=7 ctermbg=8 guifg=#b2b2b2 guibg=#eeeeee
hi! QuickDefaultHelp ctermfg=247 guifg=#959173
" hi! QuickDefaultBorder ctermfg=31 ctermbg=252 guifg=#0087af guibg=#d0d0d0
" hi! QuickDefaultBorder ctermfg=31 ctermbg=252 guifg=#222222 guibg=#d0d0d0
hi! QuickDefaultBorder ctermfg=24 ctermbg=252 guifg=#005f87 guibg=#d0d0d0
" hi! QuickDefaultBorder ctermfg=24 ctermbg=252 guifg=#d70087 guibg=#d0d0d0
" hi! QuickDefaultTermBorder ctermfg=24 ctermbg=252 guifg=#005f87 guibg=#d0d0d0
hi! QuickDefaultTermBorder ctermfg=51 guifg=cyan
if &background == 'dark'
hi! QuickDefaultPreview ctermbg=237 guibg=#4c4846
else
hi! QuickDefaultPreview ctermbg=12 guibg=#dddddd
endif
hi! QuickDefaultMatch0 ctermfg=166 guifg=#d75f00
hi! QuickDefaultMatch1 ctermfg=31 guifg=#0087af
hi! QuickDefaultMatch2 ctermfg=25 guifg=#005faf
hi! QuickDefaultMatch3 ctermfg=64 guifg=#5f8700
hi! QuickDefaultMatch4 ctermfg=91 guifg=#8700af
hi! QuickDefaultMatch5 ctermfg=247 guifg=#a2a2a2
hi! QuickDefaultInput ctermfg=254 ctermbg=24 guifg=#e4e4e4 guibg=#005f87
hi! QuickDefaultCursor ctermfg=238 ctermbg=222 guifg=#444444 guibg=#ffd787
hi! QuickDefaultVisual ctermfg=31 ctermbg=255 guifg=#0087af guibg=#eeeeee

View File

@ -0,0 +1,19 @@
hi! QuickDefaultBackground ctermfg=235 ctermbg=246 guifg=#073642 guibg=#839496
hi! QuickDefaultSel ctermfg=254 ctermbg=241 guifg=#eee8d5 guibg=#586e75
hi! QuickDefaultKey ctermfg=166 guifg=#cb4b16
hi! QuickDefaultDisable ctermfg=242 guifg=#586e75
hi! QuickDefaultHelp ctermfg=32 guifg=#268bd2
hi! QuickDefaultBorder ctermfg=235 ctermbg=246 guifg=#073642 guibg=#839496
hi! QuickDefaultTermBorder ctermfg=235 ctermbg=246 guifg=#073642 guibg=#839496
if &background == 'dark'
hi! QuickDefaultPreview ctermbg=237 guibg=#4c4846
else
hi! QuickDefaultPreview ctermbg=12 guibg=#dddddd
endif
hi! QuickDefaultInput ctermfg=244 ctermbg=234 guifg=#839496 guibg=#002b36
hi! QuickDefaultCursor ctermfg=234 ctermbg=234 guifg=#002b36 guibg=#839496
hi! QuickDefaultVisual ctermfg=234 ctermbg=239 guifg=#002b36 guibg=DarkGray

View File

@ -0,0 +1,21 @@
hi! link QuickDefaultBackground Pmenu
hi! link QuickDefaultSel PmenuSel
hi! link QuickDefaultKey Title
hi! link QuickDefaultDisable Comment
hi! link QuickDefaultHelp Conceal
hi! link QuickDefaultBorder Pmenu
hi! link QuickDefaultTermBorder Pmenu
if &background == 'dark'
hi! QuickDefaultPreview ctermbg=237 guibg=#4c4846
else
hi! QuickDefaultPreview ctermbg=12 guibg=#dddddd
endif
hi! link QuickDefaultInput NonText
hi! link QuickDefaultCursor Cursor
hi! link QuickDefaultVisual Visual

View File

@ -1,3 +1 @@
au BufRead,BufNewFile *.hsc set filetype=haskell
au BufRead,BufNewFile *.bpk set filetype=haskell
au BufRead,BufNewFile *.hsig set filetype=haskell
au BufRead,BufNewFile *.hsc,*.bpk,*.hsig set filetype=haskell

View File

@ -0,0 +1,4 @@
augroup nim_vim
au BufNewFile,BufRead *.nim,*.nims,*.nimble set filetype=nim
augroup END

View File

@ -0,0 +1 @@
au BufRead,BufNewFile *.py set noexpandtab

View File

@ -1,2 +1,4 @@
runtime! ftplugin/html.vim
autocmd BufNewFile,BufRead *.xml,*ui
\ runtime! ftplugin/html.vim |
\ let g:xml_syntax_folding=1 |
\ set foldmethod=syntax

View File

@ -9,27 +9,31 @@ input_filename = ''
preprocessor='clang -fdirectives-only -E {input_} -o {output}'
tags_filename = 'vim.tags'
polution_directory = './'
action = 'hi'
def print2(s):
print(s, file=sys.stderr)
def usage(name, x):
print2("Usage: {0} <options>".format(name))
print2("Usage: {0} <options> <verb>".format(name))
print2("\t-h")
print2("\t-i <file>")
print2("\t-p <cmd>")
print2("\t-t <path>")
print2("\t-i <file> : input")
print2("\t-p <cmd> : preprocessor (e.g.: 'clang -fdirectives-only -E {input_} -o {output}')")
print2("\t-t <path> : polution directory")
print2("\t---")
print2("\thi")
print2("\tsig")
exit(x)
def opts(args):
global input_filename, preprocessor, polution_directory
global input_filename, preprocessor, polution_directory, action
try:
i = args.index("--help") if "--help" in args else -1
if i != -1:
usage(args[0], 1)
else:
for idx, arg in enumerate(args[1:]):
for idx, arg in enumerate(args[1:]): # this is terrible
if arg in ("-h", "--help"):
usage(args[0], 0)
elif arg == "-i":
@ -38,6 +42,10 @@ def opts(args):
preprocessor = args[idx + 2]
elif arg == "-t":
polution_directory = args[idx + 2]
elif arg == "hi":
action = "hi"
elif arg == "sig":
action = "sig"
except IndexError:
usage(args[0], 1)
if input_filename == '':
@ -79,7 +87,7 @@ targets = [
'type': 'u',
'out': hi('Type')
},
{
{
'type': 'g',
'out': hi('Type')
},
@ -92,15 +100,16 @@ targets = [
'out': hi('Identifier')
},
]
PATTERN_INDEX = 1 - 1
TYPE_INDEX = 4 - 1
NAME_INDEX = (1) - 1
PATTERN_INDEX = (3) - 1
TYPE_INDEX = (4) - 1
def do_ignore(row):
IGNORE_IF_BEGINS_WITH = '!_'
for i in IGNORE_IF_BEGINS_WITH:
if row[0][0] == i:
return True
if row[PATTERN_INDEX].find('operator') != -1:
if row[NAME_INDEX].find('operator') != -1:
return True
return False
@ -131,7 +140,7 @@ def file2tags(filename, flags):
def tags2hi(filename):
output = set()
print2(filename)
#print2(filename)
try:
with open(filename) as f:
csv_reader = csv.reader(f, delimiter='\t')
@ -141,14 +150,41 @@ def tags2hi(filename):
for t in targets:
try:
if t['type'] == row[TYPE_INDEX]:
output.add(render(t, re.escape(row[PATTERN_INDEX])))
output.add(render(t, re.escape(row[NAME_INDEX])))
except:
print2(row)
#print2(row)
pass
except FileNotFoundError as e:
print2(sys.argv[0] + ": No such file or directory '{0}'.".format(filename))
exit(1)
return output
def pattern2signature(name, pattern):
start = pattern.find(name)
if pattern.find(')') != -1:
end = pattern.find(')') + 1
else:
end = pattern.find('$')
return pattern[start : end]
has_signature = ['f', 'p']
def tags2sigs(filename):
output = dict()
#print2(filename)
with open(filename) as f:
csv_reader = csv.reader(f, delimiter='\t')
for row in csv_reader:
if do_ignore(row):
continue
if row[TYPE_INDEX] in has_signature:
signature = pattern2signature(row[NAME_INDEX], row[PATTERN_INDEX])
if row[NAME_INDEX] in output:
output[row[NAME_INDEX]].append(signature)
else:
output[row[NAME_INDEX]] = [signature]
return output
def main(argv):
global input_filename
opts(argv)
@ -162,9 +198,12 @@ def main(argv):
if language != '':
input_filename = preprocessfile(input_filename)
flags += ' --language-force={0} '.format(language)
output = tags2hi(file2tags(input_filename, flags))
output = sorted(output)
output = '\n'.join(output)
if action == 'hi':
output = tags2hi(file2tags(input_filename, flags))
output = sorted(output)
output = '\n'.join(output)
elif action == 'sig':
output = "let signatures = " + str(tags2sigs(file2tags(input_filename, flags)))
print(output)
if __name__ == '__main__':

View File

@ -0,0 +1,33 @@
" NOTE: keys() & values() return their results in arbitrary order
let s:colorKeys = ['red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'black', 'white', 'bold', 'italics', 'normal', 'reverse']
let s:colorValues = [ '31', '32', '33', '34', '35', '36', '30', '37', '1', '3', '0', '7']
function! s:ColorSelected(id, result)
let val = '\033[' . s:colorValues[a:result-1] . 'm'
exec 'normal! i' . val
endfunction
function! ShowEscapeDictionary()
call popup_menu(s:colorKeys, #{
\ callback: 's:ColorSelected',
\ })
endfunction
command! ShowEscapeDictionary call ShowEscapeDictionary()
let s:makeKeys = ['target', 'star', 'first pre.', 'all new pre.', 'all pre.', 'uniq all pre.', 'basename target']
let s:makeValues = [ '@', '%', '<', '?', '+', '^', '*']
function! s:MakeSelected(id, result)
let val = '$' . s:makeValues[a:result-1]
exec 'normal! i' . val
endfunction
function! ShowMakeDictionary()
call popup_menu(s:makeKeys, #{
\ callback: 's:MakeSelected',
\ })
endfunction
command! ShowMakeDictionary call ShowMakeDictionary()

View File

@ -11,28 +11,83 @@
" otherwise you are responsible for creating your own
let s:polution_directory = expand('~/.vim/plugin/HiTags/')
" Compiler to use for preprocessing C/C++, so headers are respected
" Either use "clang" or "gcc" or something compatible,
" alternatively you will have to edit s:preprocessor
let s:preprocessor_executable = "clang"
" Compiler_Collection_based_Preprocessing:
if 0
" Compiler to use for preprocessing C/C++, so headers are respected
" Either use "clang" or "gcc" or something compatible,
" alternatively you will have to edit s:preprocessor
let s:preprocessor_executable = "clang"
"let s:preprocessor_executable = "gcc"
let s:preprocessor = s:preprocessor_executable . ' -fdirectives-only -E {input_} -o {output}'
endif
" Stand_alone_preprocessor:
" The only implementation i know is fcpp (https://github.com/bagder/fcpp.git)
" However, it has the major advantage that it will only warn on missing
" headers and not error. Meaning a tool chain using '-I' doesn't break
" everything.
let s:preprocessor = "fcpp -LL {input_} {output}"
" --- --------------------------- ---
" --- Don't Touch ---
" --- Unless ---
" --- You know What You Are Doing ---
" --- --------------------------- ---
let s:preprocessor = s:preprocessor_executable . ' -fdirectives-only -E {input_} -o {output}'
let s:tags_filename = 'tags'
let s:tags_file = expand(s:polution_directory) . s:tags_filename
let s:tags_scriptname = 'tags.vim'
let s:tags_script = expand(s:polution_directory) . 'tags.vim'
let s:sigs_script = expand(s:polution_directory) . 'sigs.vim'
"
let s:generator_script = expand('~/.vim/plugin/HiTags/hitags.py')
let s:generation_command = 'python ' . s:generator_script .
let s:generation_command =
\ 'python ' . s:generator_script .
\ ' -i ' . '"' . expand('%:p') . '"' .
\ ' -p ' . '"' . s:preprocessor . '"' .
\ ' -t ' . '"' . s:polution_directory . '"' .
\ ' > ' . '"' . s:tags_script . '"'
\ ' hi ' .
\ ' > ' . '"' . s:tags_script . '"' .
\ ';' .
\ 'python ' . s:generator_script .
\ ' -i ' . '"' . expand('%:p') . '"' .
\ ' -p ' . '"' . s:preprocessor . '"' .
\ ' -t ' . '"' . s:polution_directory . '"' .
\ ' sig ' .
\ ' > ' . '"' . s:sigs_script . '"'
" --- Signature stuff ---
function! SigDebug()
echo s:generation_command
endfunction
function! SigInit()
let g:signatures = {}
autocmd TextChangedI * call SigPopup()
endfunction
call SigInit()
function! SigPopup()
let key = matchstr(getline('.')[:col('.')-2], '\k\+$')
if has_key(g:signatures, key)
call popup_atcursor(g:signatures[key], #{} )
endif
endfunction
function! Sig()
execute 'source ' . s:sigs_script
endfunction
if exists('g:sigs_events')
for e in g:sigs_events
execute "autocmd " . e . " * Sig"
endfor
endif
command! Sig :call Sig()
" --- --- ---
function! HiTagsUpdate()
let pid = system(s:generation_command)

104
vim/.vim/plugin/quickui.vim Normal file
View File

@ -0,0 +1,104 @@
"======================================================================
"
" quickui.vim -
"
" Created by skywind on 2019/12/26
" Last Modified: 2021/12/08 23:01
"
"======================================================================
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
" require vim 8.2+
if has('patch-8.2.1') == 0 || has('nvim')
" finish
endif
"----------------------------------------------------------------------
" exports
"----------------------------------------------------------------------
let g:quickui_version = '1.4.3'
"----------------------------------------------------------------------
" internals
"----------------------------------------------------------------------
let s:home = fnamemodify(resolve(expand('<sfile>:p')), ':h')
let s:rtp = fnamemodify(s:home, ':h')
"----------------------------------------------------------------------
" QuickUI command
"----------------------------------------------------------------------
command! -bang -nargs=* -complete=customlist,quickui#command#complete
\ QuickUI call quickui#command#run('<bang>', <q-args>)
"----------------------------------------------------------------------
" setup variables
"----------------------------------------------------------------------
let g:quickui#style#border = get(g:, 'quickui_border_style', 1)
function! s:set_quickui_hi()
" hi! QuickDefaultSel ctermbg=
hi! link QuickBG QuickDefaultBackground
hi! link QuickSel QuickDefaultSel
hi! link QuickKey QuickDefaultKey
hi! link QuickOff QuickDefaultDisable
hi! link QuickHelp QuickDefaultHelp
hi! link QuickBorder QuickDefaultBorder
hi! link QuickTermBorder QuickDefaultTermBorder
hi! link QuickPreview QuickDefaultPreview
" for input box
hi! link QuickInput QuickDefaultInput
hi! link QuickCursor QuickDefaultCursor
hi! link QuickVisual QuickDefaultVisual
endfunc
function! QuickThemeChange(theme)
let theme = 'default'
if a:theme == ''
let theme = 'default'
elseif a:theme == 'default' || a:theme == 'ansi'
let theme = 'default'
elseif a:theme == 'borland' || a:theme == 'turboc'
let theme = 'borland'
elseif a:theme == 'colorscheme' || a:theme == 'system' || a:theme == 'vim'
let theme = 'system'
elseif a:theme == 'gruvbox'
let theme = 'gruvbox'
elseif a:theme == 'solarized'
let theme = 'solarized'
elseif a:theme == 'papercol' || a:theme == 'papercol-dark'
let theme = 'papercol_dark'
elseif a:theme == 'papercol dark'
let theme = 'papercol_dark'
elseif a:theme == 'papercol-light' || a:theme == 'papercol light'
let theme = 'papercol_light'
else
let theme = a:theme
endif
let s:fname = s:rtp . '/colors/quickui/' . theme . '.vim'
if !filereadable(s:fname)
let s:fname = s:rtp . '/colors/quickui/borland.vim'
endif
if filereadable(s:fname)
exec "source " . fnameescape(s:fname)
endif
call s:set_quickui_hi()
endfunc
let s:scheme = get(g:, 'quickui_color_scheme', '')
call QuickThemeChange(s:scheme)
augroup quickui "{{{
autocmd!
autocmd Colorscheme * call QuickThemeChange(get(g:, 'quickui_color_scheme', ''))
augroup END "}}}
call s:set_quickui_hi()

View File

@ -186,7 +186,8 @@ endfunction
call TextEnableCodeSnip('html')
call TextEnableCodeSnip('php')
call TextEnableCodeSnip('sql')
"call TextEnableCodeSnip('sh') " this breaks some highlighting
call TextEnableCodeSnip('sh') " this breaks some highlighting
call TextEnableCodeSnip('python') " this breaks some highlighting

205
vim/.vim/syntax/nim.vim Normal file
View File

@ -0,0 +1,205 @@
" For version 5.x: Clear all syntax items
" For version 6.x: Quit when a syntax file was already loaded
if v:version < 600
syntax clear
elseif exists('b:current_syntax')
finish
endif
" Keep user-supplied options
if !exists('nim_highlight_numbers')
let nim_highlight_numbers = 1
endif
if !exists('nim_highlight_builtins')
let nim_highlight_builtins = 1
endif
if !exists('nim_highlight_exceptions')
let nim_highlight_exceptions = 1
endif
if !exists('nim_highlight_space_errors')
let nim_highlight_space_errors = 1
endif
if !exists('nim_highlight_special_vars')
let nim_highlight_special_vars = 1
endif
if exists('nim_highlight_all')
let nim_highlight_numbers = 1
let nim_highlight_builtins = 1
let nim_highlight_exceptions = 1
let nim_highlight_space_errors = 1
let nim_highlight_special_vars = 1
endif
syn region nimBrackets contained extend keepend matchgroup=Bold start=+\(\\\)\@<!\[+ end=+]\|$+ skip=+\\\s*$\|\(\\\)\@<!\\]+ contains=@tclCommandCluster
syn keyword nimKeyword addr and as asm atomic
syn keyword nimKeyword bind block break
syn keyword nimKeyword case cast concept const continue converter
syn keyword nimKeyword defer discard distinct div do
syn keyword nimKeyword elif else end enum except export
syn keyword nimKeyword finally for from
syn keyword nimKeyword generic
syn keyword nimKeyword if import in include interface is isnot iterator
syn keyword nimKeyword let
syn keyword nimKeyword mixin using mod
syn keyword nimKeyword nil not notin
syn keyword nimKeyword object of or out
syn keyword nimKeyword proc func method macro template nextgroup=nimFunction skipwhite
syn keyword nimKeyword ptr
syn keyword nimKeyword raise ref return
syn keyword nimKeyword shared shl shr static
syn keyword nimKeyword try tuple type
syn keyword nimKeyword var vtref vtptr
syn keyword nimKeyword when while with without
syn keyword nimKeyword xor
syn keyword nimKeyword yield
syn match nimFunction "[a-zA-Z_][a-zA-Z0-9_]*" contained
syn match nimClass "[a-zA-Z_][a-zA-Z0-9_]*" contained
syn keyword nimRepeat for while
syn keyword nimConditional if elif else case of
syn keyword nimOperator and in is not or xor shl shr div
syn match nimComment "#.*$" contains=nimTodo,@Spell
syn region nimComment start="#\[" end="\]#" contains=nimTodo,@Spell
syn keyword nimTodo TODO FIXME XXX contained
syn keyword nimBoolean true false
" Strings
syn region nimString start=+'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=nimEscape,nimEscapeError,@Spell
syn region nimString start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=nimEscape,nimEscapeError,@Spell
syn region nimString start=+"""+ end=+"""+ keepend contains=nimEscape,nimEscapeError,@Spell
syn region nimRawString matchgroup=Normal start=+[rR]"+ end=+"+ skip=+\\\\\|\\"+ contains=@Spell
syn match nimEscape +\\[abfnrtv'"\\]+ contained
syn match nimEscape "\\\o\{1,3}" contained
syn match nimEscape "\\x\x\{2}" contained
syn match nimEscape "\(\\u\x\{4}\|\\U\x\{8}\)" contained
syn match nimEscape "\\$"
syn match nimEscapeError "\\x\x\=\X" display contained
if nim_highlight_numbers == 1
" numbers (including longs and complex)
let s:dec_num = '\d%(_?\d)*'
let s:int_suf = '%(''%(%(i|I|u|U)%(8|16|32|64)|u|U))'
let s:float_suf = '%(''%(%(f|F)%(32|64|128)?|d|D))'
let s:exp = '%([eE][+-]?'.s:dec_num.')'
exe 'syn match nimNumber /\v<0[bB][01]%(_?[01])*%('.s:int_suf.'|'.s:float_suf.')?>/'
exe 'syn match nimNumber /\v<0[ocC]\o%(_?\o)*%('.s:int_suf.'|'.s:float_suf.')?>/'
exe 'syn match nimNumber /\v<0[xX]\x%(_?\x)*%('.s:int_suf.'|'.s:float_suf.')?>/'
exe 'syn match nimNumber /\v<'.s:dec_num.'%('.s:int_suf.'|'.s:exp.'?'.s:float_suf.'?)>/'
exe 'syn match nimNumber /\v<'.s:dec_num.'\.'.s:dec_num.s:exp.'?'.s:float_suf.'?>/'
unlet s:dec_num s:int_suf s:float_suf s:exp
endif
if nim_highlight_builtins == 1
" builtin functions, types and objects, not really part of the syntax
syn keyword nimBuiltin int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64
syn keyword nimBuiltin bool void chr char string cstring pointer range array openarray openArray seq varargs varArgs
syn keyword nimBuiltin set Byte Natural Positive Conversion
syn keyword nimBuiltin BiggestInt BiggestFloat cchar cschar cshort cint csize cuchar cushort
syn keyword nimBuiltin clong clonglong cfloat cdouble clongdouble cuint culong culonglong cchar
syn keyword nimBuiltin CompileDate CompileTime nimversion nimVersion nimmajor nimMajor
syn keyword nimBuiltin nimminor nimMinor nimpatch nimPatch cpuendian cpuEndian hostos hostOS hostcpu hostCPU inf
syn keyword nimBuiltin neginf nan QuitSuccess QuitFailure dbglinehook dbgLineHook stdin
syn keyword nimBuiltin stdout stderr defined new high low sizeof succ pred
syn keyword nimBuiltin inc dec newseq newSeq len incl excl card ord chr ze ze64
syn keyword nimBuiltin tou8 toU8 tou16 toU16 tou32 toU32 abs min max add repr
syn match nimBuiltin "\<contains\>"
syn keyword nimBuiltin tofloat toFloat tobiggestfloat toBiggestFloat toint toInt tobiggestint toBiggestInt
syn keyword nimBuiltin addquitproc addQuitProc
syn keyword nimBuiltin copy setlen setLen newstring newString zeromem zeroMem copymem copyMem movemem moveMem
syn keyword nimBuiltin equalmem equalMem alloc alloc0 realloc dealloc assert
syn keyword nimBuiltin typedesc typed untyped stmt expr
syn keyword nimBuiltin echo swap getrefcount getRefcount getcurrentexception getCurrentException Msg
syn keyword nimBuiltin getoccupiedmem getOccupiedMem getfreemem getFreeMem gettotalmem getTotalMem isnil isNil seqtoptr seqToPtr
syn keyword nimBuiltin find pop GC_disable GC_enable GC_fullCollect
syn keyword nimBuiltin GC_setStrategy GC_enableMarkAndSweep GC_Strategy
syn keyword nimBuiltin GC_disableMarkAnd Sweep GC_getStatistics GC_ref
syn keyword nimBuiltin GC_ref GC_ref GC_unref GC_unref GC_unref quit
syn keyword nimBuiltin OpenFile OpenFile CloseFile EndOfFile readChar
syn keyword nimBuiltin FlushFile readfile readFile readline readLine write writeln writeLn writeline writeLine
syn keyword nimBuiltin getfilesize getFileSize ReadBytes ReadChars readbuffer readBuffer writebytes writeBytes
syn keyword nimBuiltin writechars writeChars writebuffer writeBuffer setfilepos setFilePos getfilepos getFilePos
syn keyword nimBuiltin filehandle fileHandle countdown countup items lines
syn keyword nimBuiltin FileMode File RootObj FileHandle ByteAddress Endianness
endif
if nim_highlight_exceptions == 1
" builtin exceptions and warnings
syn keyword nimException E_Base EAsynch ESynch ESystem EIO EOS
syn keyword nimException ERessourceExhausted EArithmetic EDivByZero
syn keyword nimException EOverflow EAccessViolation EAssertionFailed
syn keyword nimException EControlC EInvalidValue EOutOfMemory EInvalidIndex
syn keyword nimException EInvalidField EOutOfRange EStackOverflow
syn keyword nimException ENoExceptionToReraise EInvalidObjectAssignment
syn keyword nimException EInvalidObject EInvalidLibrary EInvalidKey
syn keyword nimException EInvalidObjectConversion EFloatingPoint
syn keyword nimException EFloatInvalidOp EFloatDivByZero EFloatOverflow
syn keyword nimException EFloatInexact EDeadThread EResourceExhausted
syn keyword nimException EFloatUnderflow
endif
if nim_highlight_space_errors == 1
" trailing whitespace
syn match nimSpaceError display excludenl "\S\s\+$"ms=s+1
" any tabs are illegal in nim
syn match nimSpaceError display "\t"
endif
if nim_highlight_special_vars
syn keyword nimSpecialVar result
endif
syn sync match nimSync grouphere NONE "):$"
syn sync maxlines=200
syn sync minlines=2000
if v:version >= 508 || !exists('did_nim_syn_inits')
if v:version <= 508
let did_nim_syn_inits = 1
command -nargs=+ HiLink hi link <args>
else
command -nargs=+ HiLink hi def link <args>
endif
" The default methods for highlighting. Can be overridden later
HiLink nimBrackets Operator
HiLink nimKeyword Keyword
HiLink nimFunction Function
HiLink nimConditional Conditional
HiLink nimRepeat Repeat
HiLink nimString String
HiLink nimRawString String
HiLink nimBoolean Boolean
HiLink nimEscape Special
HiLink nimOperator Operator
HiLink nimPreCondit PreCondit
HiLink nimComment Comment
HiLink nimTodo Todo
HiLink nimDecorator Define
HiLink nimSpecialVar Identifier
if nim_highlight_numbers == 1
HiLink nimNumber Number
endif
if nim_highlight_builtins == 1
HiLink nimBuiltin Number
endif
if nim_highlight_exceptions == 1
HiLink nimException Exception
endif
if nim_highlight_space_errors == 1
HiLink nimSpaceError Error
endif
delcommand HiLink
endif
let b:current_syntax = 'nim'

View File

@ -1,229 +1,280 @@
" -------------
" ### LOOKS ###
" -------------
set title
"set titlestring=Vim
set iconstring=Vim
set title
"set titlestring=Vim
set iconstring=Vim
set tabstop=4
set shiftwidth=4
set expandtab
set listchars=tab:<·>,eol,space,nbsp:⎵
set listchars=tab:<·>,eol,space,nbsp:⎵
syntax on
syntax on
set nowrap "do not wrap lines not fitting the screen
set sidescroll=1 "do not jump half a screens whenever manuvering a line not fitting the screen
set nowrap "do not wrap lines not fitting the screen
set sidescroll=1 "do not jump half a screens whenever manuvering a line not fitting the screen
set display=uhex "display hex chats as <[hex]> instead of ^C and ~C
set display=uhex "display hex chats as <[hex]> instead of ^C and ~C
set laststatus=2 "display status bar
set ruler
"set statusline+=%l,%c%V%=%P
set laststatus=2 "display status bar
set ruler
"set statusline+=%l,%c%V%=%P
set visualbell "flash instead of beeping; im not sure whether thats great or annoying
set visualbell "flash instead of beeping; im not sure whether thats great or annoying
"autocmd InsertEnter * silent !echo -ne "\e[1 q"
"autocmd InsertLeave * silent !echo -ne "\e[0 q"
let &t_VS = "\e[0 q"
let &t_SI = "\e[1 q"
let &t_EI = "\e[0 q"
"autocmd InsertEnter * silent !echo -ne "\e[1 q"
"autocmd InsertLeave * silent !echo -ne "\e[0 q"
let &t_VS = "\e[0 q"
let &t_SI = "\e[1 q"
let &t_EI = "\e[0 q"
set showmatch "highlight pair of paranthesies
set hlsearch "highlight search
set wildmenu "visual command auto complete
set showmatch "highlight pair of paranthesies
set hlsearch "highlight search
set wildmenu "visual command auto complete
se nostartofline "Do not jump to first char of line when scolling
se nostartofline "Do not jump to first char of line when scolling
set colorcolumn=100 " pseudo margin at 80
set colorcolumn=100 " pseudo margin at 80
colorscheme knight
colorscheme knight
set signcolumn=no
set signcolumn=no
set shortmess-=S "show match count on search
set shortmess-=S "show match count on search
" --------------------
" ### EASSE_OF_USE ###
" --------------------
set bs=2
set undodir=/home/anon/stow/.cache/
set undofile
set bs=2
set undodir=/home/anon/stow/.cache/
set undofile
set directory=/home/anon/stow/.cache/
set backupdir=/home/anon/stow/.cache/
set directory=/home/anon/stow/.cache/
set backupdir=/home/anon/stow/.cache/
set autoindent
set autoindent
set ignorecase "ignore case in searches
set smartcase "override ignorecase when upper case letters are used in the search
set wildignorecase "ignore case when auto completing file and directory names (does not to shells)
set ignorecase "ignore case in searches
set smartcase "override ignorecase when upper case letters are used in the search
set wildignorecase "ignore case when auto completing file and directory names (does not to shells)
set autoread "chech for external changes in the file
set autoread "chech for external changes in the file
set autochdir
set autochdir
set confirm "when quiting an unsaved filed, do not fail, instead ask back whether the buffer shall be saved, not saved, or cancel the operation
set confirm "when quiting an unsaved filed, do not fail, instead ask back whether the buffer shall be saved, not saved, or cancel the operation
set noexpandtab
set mouse=a
nnoremap <LeftMouse> <nop>
set mouse=a
nnoremap <LeftMouse> <nop>
set keywordprg=:call\ ContextualMan()\ \" " better 'K' help
set keywordprg=:call\ ContextualMan()\ \" " better 'K' help
set suffixes+=.info,.aux,.log,.dvi,.bbl,.out,.o,.lo,.obj " ignore on completion
set suffixes+=.info,.aux,.log,.dvi,.bbl,.out,.o,.lo,.obj " ignore on completion
set foldopen-=hor " do not unfold on horizontal movement
set foldopen-=hor " do not unfold on horizontal movement
" always respect # pragma region
set foldmarker=#pragma\ region,#pragma\ endregion
set foldmethod=marker
" always respect # pragma region
set foldmarker=#pragma\ region,#pragma\ endregion
set foldmethod=marker
" tabs/spaces
set tabstop=4
set shiftwidth=4
set expandtab
set softtabstop=4
" -----------------
" ### Functions ###
" -----------------
function ContextualMan()
let word = expand('<cword>')
let cmd = ":silent !"
function ContextualMan()
let word = expand('<cword>')
let cmd = ":silent !"
if &filetype == "cpp"
let cmd .= "man 3 " . word . "; [ $? == 16 ] && cppman "
elseif &filetype == "python"
let cmd .= "pydoc "
else
if &filetype == "bash" || &filetype == "sh"
let cmd .= "man 1 "
else
let cmd .= "man 3 "
endif
endif
if &filetype == "vim"
:help word
return
endif
let cmd .= word
if &filetype == "cpp"
let cmd .= "man -s 3,2 " . word . "; [ $? == 16 ] && cppman "
elseif &filetype == "python"
let cmd .= "pydoc "
else
if &filetype == "bash" || &filetype == "sh"
let cmd .= "man 1 "
else
let cmd .= "man 3 "
endif
endif
execute cmd
redraw!
endfunction
let cmd .= word
function! Signcolumn_toggle()
if &signcolumn == 'no'
set signcolumn=yes
elseif &signcolumn == 'yes'
set signcolumn=no
endif
endfunction
execute cmd
redraw!
endfunction
let s:drawit_boolean = 0
function! Drawit_toggle()
if s:drawit_boolean
DIstop
let s:drawit_boolean = 0
else
DIstart
let s:drawit_boolean = 1
endif
endfunction
function! Signcolumn_toggle()
if &signcolumn == 'no'
set signcolumn=yes
elseif &signcolumn == 'yes'
set signcolumn=no
endif
endfunction
let s:acp_boolean = 0
function! Acp_toggle()
if s:drawit_boolean
AcpDisable
let s:drawit_boolean = 0
else
AcpEnable
let s:drawit_boolean = 1
endif
endfunction
function! Drawit_toggle()
if !exists("s:drawit_boolean")
let s:drawit_boolean = 0
endif
if s:drawit_boolean
DIstop
let s:drawit_boolean = 0
else
DIstart
let s:drawit_boolean = 1
endif
endfunction
let s:spell_boolean = 0
function! Spell_toggle()
if s:drawit_boolean
set nospell
let s:drawit_boolean = 0
else
set spell spelllang=en_us
let s:drawit_boolean = 1
endif
endfunction
function! Programming_mode_toggle()
if !exists("s:programming_mode_boolean")
let s:programming_mode_boolean = 0
endif
if s:programming_mode_boolean
let s:programming_mode_boolean = 0
AcpDisable
else
let s:programming_mode_boolean = 1
AcpEnable
endif
endfunction
function! Spell_toggle()
if !exists("s:spell_boolean")
let s:spell_boolean = 0
endif
if s:spell_boolean
set nospell
let s:spell_boolean = 0
else
set spell spelllang=en_us
let s:spell_boolean = 1
endif
endfunction
" --------------
" ### REMAPS ###
" --------------
" Diff_mode:
if &diff
map <C-p> :diffput<CR>
map <C-n> :diffget<CR>
endif
" Complete_on_tab:
inoremap <expr> <TAB> pumvisible() ? "<C-y>" : "<TAB>"
inoremap <expr> <CR> pumvisible() ? "\<C-g>u\<CR>" : "\<C-g>u\<CR>"
inoremap <expr> <C-j> pumvisible() ? "\<C-N>" : "<C-j>"
inoremap <expr> <C-k> pumvisible() ? "\<C-P>" : "<C-k>"
" Function_keys:
" ### Visibility island
" F1: toggle whitespace visibility
map <F1> :set invlist<CR>
" F2: toggle visible line numbers
map <F2> :set nu!<CR>
" F3: toggle sign column
map <F3> :call Signcolumn_toggle()<CR>
" F4: unhighligh highlighted text
map <F4> :noh<CR>
" ### Feature island
" F5: toggle spell check
"map <F5> :!aspell check %<CR>:e! %<CR>
map <F5> :call Spell_toggle()<CR>
" F6: reload ctags and its highlighting
map <f6> :call Cpp_tags_run()<CR>
" F7: toggle DrawIt plugin mode
map <F7> :call Drawit_toggle()<CR>
" F8: toggle acp (auto suggest) plugin mode
map <F8> :call Acp_toggle()<CR>
" ### Call once in a while island
" F9: copy file contents to clipboard
map <F9> miggVG"+y'izz
" F12: reload file
map <F12> :e!<CR>
" Tagbar_plugin:
nmap <C-W>m :TagbarToggle<CR>
" Diff_mode:
if &diff
map <C-p> :diffput<CR>
map <C-n> :diffget<CR>
endif
" Complete_on_tab:
inoremap <expr> <TAB> pumvisible() ? "<C-y>" : "<TAB>"
inoremap <expr> <CR> pumvisible() ? "\<C-g>u\<CR>" : "\<C-g>u\<CR>"
inoremap <expr> <C-j> pumvisible() ? "\<C-N>" : "<C-j>"
inoremap <expr> <C-k> pumvisible() ? "\<C-P>" : "<C-k>"
" Function_keys:
" ### Visibility island
" F1: toggle whitespace visibility
map <F1> :set invlist<CR>
" F2: toggle visible line numbers
map <F2> :set nu!<CR>
" F3: toggle sign column
map <F3> :call Signcolumn_toggle()<CR>
" F4: unhighligh highlighted text
map <F4> :noh<CR>
" ### Feature island
" F5: Display Turbo Menu
map <F5> :call quickui#menu#open()<CR>
" F6: compile with bake
map <f6> :!bake %:p<CR>
" F7:
" NOTHING YET
" F8: toggle acp (auto suggest) plugin mode
map <F8> :call Programming_mode_toggle()<CR>
" ### Call once in a while island
" F9: copy file contents to clipboard
map <F9> miggVG"+y'izz
" F10:
noremap <F10> <Nop>
" F11:
noremap <F11> <Nop>
" F12: reload file
"map <F12> :e!<CR>
noremap <F12> <Nop>
" Tagbar_plugin:
nmap <C-W>m :TagbarToggle<CR>
"------------------
" ### VARIABLES ###
"------------------
let $BASH_ENV = "/home/jacob/Desktop/minecraft mod/Linux/Vim/bash_aliases"
let g:hitags_events = ["BufWrite"]
let g:hitags_events = ["BufWrite"]
let g:sigs_events = ["BufWrite"]
" -------------
" ### NETRW ###
" -------------
let g:netrw_keepdir = 0
let g:netrw_banner = 0
"let g:netrw_browse_split = 2
let g:netrw_liststyle = 3
let g:netrw_keepdir = 0
let g:netrw_banner = 0
"let g:netrw_browse_split = 2
let g:netrw_liststyle = 3
" ---------------
" ### QUICKUI ###
" ---------------
call quickui#menu#install('&Edit', [
\ [ '&Drawit', ':call Drawit_toggle()'],
\ [ '&Expandtab', ':set expandtab!'],
\ [ '&Brace unf*', ':%s/\n\s*{/ {/g'],
\ ])
call quickui#menu#install('&View', [
\ [ '&Spell', ':call Spell_toggle()'],
\ [ '&Netrw', ':Lex'],
\ [ '&Diff', ':diffthis'],
\ ])
call quickui#menu#install('&Modify', [
\ [ '&Remove trailing', ':%s/\s\+$//g'],
\ [ '&Retab', ':retab!'],
\ ])
call quickui#menu#install('&Development', [
\ [ '&Ascii Escape', ':ShowEscapeDictionary'],
\ [ '&Make special', ':ShowMakeDictionary'],
\ [ '&Symbol map', ':TagbarToggle', '<C-W>m'],
\ ])
" ------------
" ### TMUX ###
" ------------
function! Fname()
if expand("%:t") != ""
return expand("%:t")
else
return "vim"
endif
if expand("%:t") != ""
return expand("%:t")
else
return "vim"
endif
endfunction
if exists('$TMUX')
autocmd BufEnter * call system('tmux rename-window ' . Fname())
autocmd VimLeave * call system('sh -c "sleep 1 && tmux setw automatic-rename" & disown')
autocmd BufEnter * let &titlestring = expand("%:t")
"set title " already called
autocmd BufEnter * call system('tmux rename-window ' . Fname())
autocmd VimLeave * call system('sh -c "sleep 1 && tmux setw automatic-rename" & disown')
autocmd BufEnter * let &titlestring = expand("%:t")
"set title " already called
endif
"---###NOTES###---
"https://vimawesome.com/plugin/syntastic#introduction
"https://vimawesome.com/plugin/syntastic#introduction
"" Souce VimScript9 settings
"source ~/.vimrc9
set formatoptions-=cro
" TEMP:
highlight DiffChange ctermbg=3
" AI notes:
" <C-W>v<C-W>l
" :new
" :windo diffthis

6
x11/x_startup.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
xset s off
xset r rate 170 45
setxkbmap -layout hu -variant nodeadkeys
setxkbmap -option caps:swapescape