在接触 Neovim 之前,我的主力编辑器一直是 Vim。在 Vim 增加 +job
特性之前,
Vim 的所有函数都是在主线程内完成的,当执行某个需要很长时间的操作时,Vim 会卡住等待上一个操作完成。
这样的体验是非常不符合个人习惯的。因此,Geoff Greer 给 Vim 提交过异步执行的补丁,源码可以查阅Floobits/vim。同时,Thiago Padilha 也给 Vim 提交过类似的补丁,但是都因各种原因被拒绝,其实这也是我不太喜欢的一个 Vim 开发的弊端。
后来,Thiago Padilha 发起了 Neovim 项目,做了如下改进:
虽然,以上的一些功能 Vim 后续也增加了,但是部分功能却是用了另外一种完全不兼容的方式。
Neovim 的异步 job 特性主要是提供了一个异步执行外部命令的函数。并且通过回调函数来响应输出的结果。比如:
call jobstart(['echo'])
Neovim 增加了一个定时器功能,主要涉及函数为 timer_start()
,其函数原型为:
timer_start({time}, {callback} [, {options}])
以往 Vim 支持垂直、水平分屏,而分屏时窗口的布局、屏幕内容都会发生改变。悬浮窗口提供了一种在不改变当前窗口布局的前提下,打开额外的窗口以展示新的内容。
Neovim 和 Vim 的分屏又是完全不一样的函数。因此我写了一个函数,来统一调用 Neovim 或者 Vim 的悬浮窗口。
if has('nvim')
let s:FLOAT = SpaceVim#api#import('neovim#floating')
else
let s:FLOAT = SpaceVim#api#import('vim#floating')
endif
call s:FLOAT.open_win(bufnr('%'), v:true,
\ {
\ 'relative': 'editor',
\ 'width' : &columns,
\ 'height' : &lines * 30 / 100,
\ 'row': 0,
\ 'col': &lines - (&lines * 30 / 100) - 2
\ })
可以通过 :terminal
命令打开内置终端。在终端窗口内,可以使用 Ctrl-\ Ctrl-n
切换到 Normal 模式。
目前,内置的:terminal
命令不支持分屏模式,可以借助split-term.vim插件。
该插件增加了如下的使用方式:
优化内置终端的插件有很多种:
虽然这些插件都挺不错的,但是个人感觉没有必要那么复杂。目前,就个人而言,我仅仅使用了 Neovim 的悬浮窗口配合 termopen 函数。
let s:SYSTEM = SpaceVim#api#import('system')
let s:FLOAT = SpaceVim#api#import('neovim#floating')
let s:WIN = SpaceVim#api#import('vim#window')
function! s:open_default_shell(open_with_file_cwd) abort
if a:open_with_file_cwd
if getwinvar(winnr(), '&buftype') ==# 'terminal'
let path = getbufvar(winbufnr(winnr()), '_spacevim_shell_cwd', SpaceVim#plugins#projectmanager#current_root())
else
let path = expand('%:p:h')
endif
else
let path = SpaceVim#plugins#projectmanager#current_root()
" if the current file is not in a project, the projectmanager return empty
" string. Then use current directory as default cwd.
if empty(path)
let path = getcwd()
endif
endif
" look for already opened terminal windows
let windows = []
windo call add(windows, winnr())
for window in windows
if getwinvar(window, '&buftype') ==# 'terminal'
exe window . 'wincmd w'
if getbufvar(winbufnr(window), '_spacevim_shell_cwd') ==# l:path
" startinsert do not work in gvim
if has('nvim')
startinsert
else
normal! a
endif
return
else
" the opened terminal window is not the one we want.
" close it, we're gonna open a new terminal window with the given l:path
exe 'wincmd c'
break
endif
endif
endfor
if s:default_position ==# 'float' && exists('*nvim_open_win')
let s:term_win_id = s:FLOAT.open_win(bufnr('%'), v:true,
\ {
\ 'relative': 'editor',
\ 'width' : &columns,
\ 'height' : &lines * s:default_height / 100,
\ 'row': 0,
\ 'col': &lines - (&lines * s:default_height / 100) - 2
\ })
exe win_id2win(s:term_win_id) . 'wincmd w'
else
" no terminal window found. Open a new window
let cmd = s:default_position ==# 'float' ?
\ 'topleft split' :
\ s:default_position ==# 'top' ?
\ 'topleft split' :
\ s:default_position ==# 'bottom' ?
\ 'botright split' :
\ s:default_position ==# 'right' ?
\ 'rightbelow vsplit' : 'leftabove vsplit'
exe cmd
let lines = &lines * s:default_height / 100
if lines < winheight(0) && (s:default_position ==# 'top' || s:default_position ==# 'bottom')
exe 'resize ' . lines
endif
endif
let w:shell_layer_win = 1
for open_terminal in s:open_terminals_buffers
if bufexists(open_terminal)
if getbufvar(open_terminal, '_spacevim_shell_cwd') ==# l:path
exe 'silent b' . open_terminal
" clear the message
if has('nvim')
startinsert
else
normal! a
endif
return
endif
else
" remove closed buffer from list
call remove(s:open_terminals_buffers, 0)
endif
endfor
" no terminal window with l:path as cwd has been found, let's open one
if s:default_shell ==# 'terminal'
if exists(':terminal')
if has('nvim')
if s:SYSTEM.isWindows
let shell = empty($SHELL) ? 'cmd.exe' : $SHELL
else
let shell = empty($SHELL) ? 'bash' : $SHELL
endif
enew
call termopen(shell, {'cwd': l:path})
" @bug cursor is not cleared when open terminal windows.
" in neovim-qt when using :terminal to open a shell windows, the orgin
" cursor position will be highlighted. switch to normal mode and back
" is to clear the highlight.
" This seem a bug of neovim-qt in windows.
"
" cc @equalsraf
if s:SYSTEM.isWindows && has('nvim')
stopinsert
startinsert
endif
let s:term_buf_nr = bufnr('%')
call extend(s:shell_cached_br, {getcwd() : s:term_buf_nr})
else
" handle vim terminal
if s:SYSTEM.isWindows
let shell = empty($SHELL) ? 'cmd.exe' : $SHELL
else
let shell = empty($SHELL) ? 'bash' : $SHELL
endif
let s:term_buf_nr = term_start(shell, {'cwd': l:path, 'curwin' : 1, 'term_finish' : 'close'})
endif
call add(s:open_terminals_buffers, s:term_buf_nr)
let b:_spacevim_shell = shell
let b:_spacevim_shell_cwd = l:path
" use WinEnter autocmd to update statusline
doautocmd WinEnter
setlocal nobuflisted nonumber norelativenumber
" use q to hide terminal buffer in vim, if vimcompatible mode is not
" enabled, and smart quit is on.
if !empty(g:spacevim_windows_smartclose) && !g:spacevim_vimcompatible
exe 'nnoremap <buffer><silent> ' . g:spacevim_windows_smartclose . ' :hide<CR>'
endif
startinsert
else
echo ':terminal is not supported in this version'
endif
elseif s:default_shell ==# 'VimShell'
VimShell
imap <buffer> <C-d> exit<esc><Plug>(vimshell_enter)
endif
endfunction
上周,听到一则让我很吃惊的消息。陈浩(左耳朵耗子)因突发心梗辞世,享年只有四十七岁。 正常情况下,四十多岁正是事业、家庭黄金时间。当财富、声望都积累足够的时候,却没有时间去享受自己奋斗的果实,确实让人觉得惋惜。
其实,对于左耳朵耗子了解的并不多,甚至可以说完全不了解。这几天,不管是朋友圈,还是推特,抑或是订阅的一些博客,都在发文纪念他。 也正是读了这些文字才有了一些了解。其实,这类事情之前已经遇到过好几次了。比如:司徒正美。
想来,真的是健康是一,财富、声望、家庭等等一切都是零。
也正是因此,最近才开始关注一些生活习惯方面的资料。包括不限于:
1、早餐:以往有时候因为熬夜,第二天早上起来的较晚,会错过酒店的早餐时间。又或者是因为早上赶时间,早餐只是应付式地吃一点,甚至是来不及吃。
给自己定一个闹铃,每天早餐预留充足时间
2、夜宵:拒绝夜宵,晚上9点后,不再进食
睡眠时间一直是一个大问题,应该是自15年之后,每天睡觉几乎都是11点半到12点半甚至1点。
想控制到10点之前,似乎是不现实的,后面尽量控制在11点-7点半,保证至少8小时睡眠。
貌似没有什么适合自己的运动了。以前偶尔还去爬山,上次去宜兴竹海,只到半山腰就下来了。
2016 年第一次接触 v2ex 的时候,觉得这个论坛做的还是非常不错的,相比老式的 BBS 论坛界面要舒服多了。于是,注册了一个账号:
https://www.v2ex.com/member/wsdjeg V2EX 第 167678 号会员,加入于 2016-04-11 13:08:11 +08:00
随着使用时间的增加,慢慢发现也许 V2EX 这样的“个人网站”并不适合我。罗列了一些存在的问题,以及个人的一些看法。
这就存在一个文字版权问题了,自己发的贴子,都无权决定他的删除与否,简直可笑。
个人认为,人的认知和观点是会随着时间的推移、知识的积累、以及所经历的事情发生改变的。 所以偶尔回头去翻看自己写下的文字,还是希望有一个更新、修改的功能。当然,可以使用类似于 Git 仓库一样,保留修改记录。
这里,我把“随意”加上了引号是因为可能有些人会认为这不是随意移贴,而是基于“某些规则”, 但是希望这个规则可以公开,并且接受大众修改意见。 否则,这给人的感觉 v2ex 就是一个站长私人的网站,只不过给了注册用户部分的编辑权限。
比如:当你发了一个帖子,讨论正火热的时候,管理员可以将帖子移至“水生火热”(https://www.v2ex.com/go/flamewar
)标签下,
这个标签下的内容,非登录用户似乎是无法查阅的,会自动跳转至首页。
社交类的平台,想必大家也不陌生。我自己以往就使用过QQ空间、人人网、朋友圈等等。这些平台有一个特点,你的好友、你所关注的人,他们的更新,会严格按照时间线展示给你。
但是 v2ex 这种降权就会很霸道,他会让你的更新出现在2天前、3天前、甚至更久之前的时间线上。结果就不言而喻了,其他人可能不会那么容易看到你所写的内容。
还有一些其他原因,后面想到再更新上来。
v2ex/faq 页面可能会修改,这里保留了 2024 年 8 月的内容:
我是否可以编辑或者移动自己的主题?
在主题发布之后的 300 秒内,你可以自由地编辑自己的主题,或者将其移动到其他节点。但是在 300 秒(5 分钟)之后,
就不可以再进行这些操作了。对于编辑的限制是为了让大家对发表在 V2EX 的言论更加负责。
简直是荒谬的理论,把完全不相干的两个事情强行联系起来。
基于这些原因,即日起停用 v2ex 账号,写到这才发现,原来 v2ex 的账号,还不提供删除功能,这也太牛氓了。
v2ex 贴子(https://v2ex.com/t/1063942)链接已被移至水生火热,非登录用户无法访问,内容如下:
使用谷歌搜索“如何删除V2EX账号”可以看到不少人遇到类似的问题。
五一期间没有来得及回家,这次周末正好是母亲节。周五晚上工作结束后,回了一趟老家,已经快半年没有回去了。
周六早上,带爷爷、奶奶、妈妈一起去扬州世博园玩玩。避开五一假期,也是另外一番景色。
中午在宝能广场吃的“老土灶民间菜”,感觉他们家菜的口味还是挺不错的,而且也比较实惠。
吃完饭回家回家后陪爷爷奶奶还有妈妈打麻将,老年人爱好挺简单的。我记得我上次打牌还是去年11月份,手生的很。
礼拜天,是母亲节,今天中午选的是无锡融创茂的泰妃餐厅。
今天向大家分享一个我刚写的 Vim 插件 gfr.vim。名字取自三个词语缩写:Grep, Filter, Replace。顾名思义,这个插件提供的功能包括文本搜索、结果筛选以及文本替换功能。
Vim 文本搜索的插件已经非常多了,我自己也使用过很多种插件。比如:ack.vim
、ag.vim
、grepper.vim
等等。这些插件都提供了类似的功能,即为搜索制定的文字,并将结果输出到 Vim 的 quickfix window。
甚至,我之前还制作过一款实时异步搜索,并展示搜索结果的插件 flygrep.vim。
但是以上这些插件仅仅支持搜索指定文本的结果,不具备二次检索和替换的功能。
这个插件中,我比较常用的命令是 :Grep
。实际上,Vim 本身也有 :grep
和 :vimgrep
命令,功能是相同的,都是执行搜索命令,并且把搜索的结果展示在 quickfix 窗口内。
但是 Vim 自带的 :grep
和 :vimgrep
命令是单线程的,如果搜索的文件夹内内容非常多会卡住当前 Vim 的操作界面,体验不是很好。
Vim 和 Neovim 的一些内置函数还是有些差异的,而 gfr.vim
集成了 SpaceVim 的 API,可以同时兼容 Vim 和 Neovim。
gfr.vim
使用了 SpaceVim 的 notify API,对于一些插件通知消息,在 Vim 右上方使用浮窗提示。
和其他常用插件一样,你可以使用任意一个插件管理器来安装,比如使用 plug.vim:
Plug 'wsdjeg/gfr.vim'
在插件列表添加上面这段即可,启动 Vim 后执行 :PlugInstall
。
gfr.vim
提供了如下命令:
:Grep
: 搜索指定的文本,该命令后面的参数即为需要搜索的文本,比如 :Grep hello
指的就是搜索 hello
。如果直接调用:Grep
,并且不带任何参数,那么会弹出一个输入框,可供输入需要搜索的文本。:Filter
:检索上一次搜索的结果,可以理解为二次筛选。对于上一次搜索或者检索的结果,进行再一次的筛选。:GrepSave
:将当前的搜索结果保存至命名标签,以便于快速访问。:GrepResum
:使用:GrepResum 标签名
可以快速打开以往的搜索结果:Replace
:对搜索到的结果执行文本替换目前,这个插件只支持 grep
命令,后续计划增加 ag
、rg
等命令支持。
五一期间花了一点点时间将微信朋友圈“移植”到博客相册,今天抽空整理了下这个过程,并记录。
微信朋友圈14年左右开始使用,至今已经十年了,出于以下原因放弃:
最起初,只有三五个相册的时候,相册页面的内容是纯手工写的。后来,当把朋友圈老照片都转移过来后,手工操作的话就不合适了。
因为相册的内容比较简单:
{日期}
{context}
{gallery}
{location}
因此,基于dev#autodoc
API 写了一个脚本:
let s:AUTODOC = SpaceVim#api#import('dev#autodoc')
let s:AUTODOC.autoformat = 0
function! Gengallery() abort
let s:AUTODOC.begin = '^<!-- wsdjeg.net gallery start -->$'
let s:AUTODOC.end = '^<!-- wsdjeg.net gallery end -->$'
let s:AUTODOC.content_func = function('s:generate_gallery')
call s:AUTODOC.update()
endfunction
function! s:generate_gallery() abort
let content = []
call extend(content, s:gallery_list())
let content += ['']
return content
endfunction
function! s:gallery_list() abort
let text = []
let gallery_dirs = globpath('docs/uploads', '*', 1, 1)
let previous_t = ''
for gpath in gallery_dirs
if empty(previous_t) || matchstr(gpath, '\d\+') !=# previous_t
call extend(text, s:dir_to_g(gpath), 0)
let previous_t = matchstr(gpath, '\d\+')
endif
endfor
return text
endfunction
function! s:dir_to_g(d) abort
let t = []
let y = str2nr(matchstr(a:d, '\d\d\d\d'))
let m = str2nr(matchstr(a:d, '\d\d\d\d\zs\d\d'))
let d = matchstr(a:d, '\d\d\d\d\d\d\zs\d\d')
call add(t, '### ' . y . '年' . m . '月' . (empty(d) ? '' : d . '日'))
call add(t, '')
" 如果存在 text.txt 文件,读取内容,写入文字
if filereadable(a:d . '/text.txt')
call extend(t, readfile(a:d . '/text.txt'))
call add(t, '')
endif
call add(t, '{% include image-gallery-nofilename.html folder="' . substitute(a:d[5:], '\', '/', 'g') . '" %}')
call add(t, '')
" 如果存在 location 文件,读取内容,写入地址
if filereadable(a:d . '/location')
call add(t, '> <i class="fa fa-map-marker"></i> ' . readfile(a:d . '/location')[0])
call add(t, '')
endif
return t
endfunction