编辑器中转到包含scope的快捷键
问题
众所周知,程序员大部分时间并不是在写代码而是在浏览和调试代码。对于一个大型项目,或者不是很熟悉的模块,浏览代码是通常需要各种跳转。
一个常见的场景时:当通过搜索(例如linux下的grep工具)或者ctag跳转到某个引用的时候,我们可能并不知道此时所在何处。比方说,是在哪个函数内,是在哪个类内部,甚至是在某个C++的lambda函数内。
此时就需要编辑器有一个功能,能够快速的告诉光标当前所处的scope/block信息。或者用类似于GPS的概念来说,就是告诉我当前我的位置在哪里。
visual assist
从visual assist中内置命令,其中有一些很有用但是之前被忽略的、默认配置了快捷键的功能。
在浏览代码的时候,经常使用的是Alt配合上左右箭头来进行前一个位置和后一个位置的跳转。和这个功能类似,Alt匹配的另外两个上下方向键却是之前忽略的命令:scope的导航。
Command | Description | Default Shortcut |
---|---|---|
ScopeNext | Move to Next Scope | Alt+Down Arrow † |
ScopePrevious | Move to Previous Scope | Alt+Up Arrow † |
SmartSelectExtend | Smart Select to initiate or extend a selection | Shift+Alt+] † |
SmartSelectExtendBlock | Smart Select to initiate or extend a block selection | Alt+] |
SmartSelectShrink | Smart Select to decrease a selection | Shift+Alt+[ † |
SmartSelectShrinkBlock | Smart Select to decrease a block selection | Alt+[ |
visual studio
va毕竟是第三方插件,对于使用原汁原味的visual Studio的用户来说,可能更喜欢或者必须使用VS自带的快捷键功能,那么VS也提供了类似的功能。
SO上说明了这个对应功能的位置,可能是由于这个功能添加比较晚,简短的组合键已经被占用,所以这个功能使用了一个相对复杂并且没有VA直观的组合键(奇怪的是这个功能并没有在visual Studio文档里列出来)。
I have a fresh install of VS2017. As of 15.9.1, the default for me is Alt+Shift+[.
This is the shortcut for EditorContextMenus.Navigate.GoToContainingBlock. So you may have to execute this shortcut multiple times if you are a few block layers deep, but it'll get you where you want to go.
不过,由于VA的很多功能其实也默认使用ALT+SHIFT的功能组合(例如,查找引用的ALT+SHIFT+F,ALT+SHIFT+O开文件搜索),所以其实使用这组快捷键也并不是很违和。
Expand selection | Shift+Alt+= |
Expand selection to containing block | Shift+Alt+] |
vim
由于vim主要是一个文本编辑器(text editor),本身并没有内置的语法分析功能,所以对于类似的block和选择功能支持相对来说可能更多,但是也更繁琐。
个人最为熟悉的还是使用方括弧来表达的block跳转,但是这种跳转明显没有VS自带block智能。
5. Text object motions object-motions
(
( [count] sentences backward. exclusive motion.
)
) [count] sentences forward. exclusive motion.
{
{ [count] paragraphs backward. exclusive motion.
}
} [count] paragraphs forward. exclusive motion.
]]
]] [count] sections forward or to the next '{' in the
first column. When used after an operator, then also
stops below a '}' in the first column. exclusive
Note that exclusive-linewise often applies.
][
][ [count] sections forward or to the next '}' in the
first column. exclusive
Note that exclusive-linewise often applies.
[[
[[ [count] sections backward or to the previous '{' in
the first column. exclusive
Note that exclusive-linewise often applies.
[]
[] [count] sections backward or to the previous '}' in
the first column. exclusive
matchit
vim的matchit扩展提供了相对原生的功能更加智能的,类似于VS的功能。它虽然不是vim默认使能的,但是它是vim自带的,也就是在vim的官方工程中是包含的,这也意味着这个功能其实是可以随时实时使用的。奇怪的是在我的版本中默认并没有这个功能。
- 搜索路径
在vim可执行文件构建的过程中,在可执行文件中预先包含了可执行文件的路径,在vim的ex模式下执行version命令,可以看到预制的搜索路径
fall-back for $VIM: "/home/tsecer/share/vim"
这个路径在构建
auto/pathdef.c: Makefile auto/config.mk
-@echo creating $@
-@echo '/* pathdef.c */' > $@
-@echo '/* This file is automatically created by Makefile' >> $@
-@echo ' * DO NOT EDIT! Change Makefile only. */' >> $@
-@echo '#include "vim.h"' >> $@
-@echo 'char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)";' | $(QUOTESED) >> $@
-@echo 'char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)";' | $(QUOTESED) >> $@
-@echo 'char_u *all_cflags = (char_u *)"$(CC) -c -I$(srcdir) $(ALL_CFLAGS)";' | $(QUOTESED) >> $@
-@echo 'char_u *all_lflags = (char_u *)"$(CC) $(ALL_LIB_DIRS) $(LDFLAGS) -o $(VIMTARGET) $(ALL_LIBS) ";' | $(QUOTESED) >> $@
-@echo 'char_u *compiled_user = (char_u *)"' | tr -d $(NL) >> $@
-@if test -n "$(COMPILEDBY)"; then \
echo "$(COMPILEDBY)" | tr -d $(NL) >> $@; \
else ((logname) 2>/dev/null || whoami) | tr -d $(NL) >> $@; fi
-@echo '";' >> $@
-@echo 'char_u *compiled_sys = (char_u *)"' | tr -d $(NL) >> $@
-@if test -z "$(COMPILEDBY)"; then hostname | tr -d $(NL) >> $@; fi
-@echo '";' >> $@
-@sh $(srcdir)/pathdef.sh
- packpath
通过packpath可以看到,确认matchit所在的文件夹也是在这个路径中的。
'packpath' 'pp'
'packpath' 'pp' string (default: see 'runtimepath')
{not in Vi}
Directories used to find packages. See packages.
- packages
在packages帮助中,明确说明了在opt文件夹下的内容是不会被自动加载的,而只是会自动加载start文件夹下的内容。但是同时也说明了可以通过packadd命令
The directory name "foo" is arbitrary, you can pick anything you like.
You would now have these files under ~/.vim:
pack/foo/README.txt
pack/foo/start/foobar/plugin/foo.vim
pack/foo/start/foobar/syntax/some.vim
pack/foo/opt/foodebug/plugin/debugger.vim
When Vim starts up, after processing your .vimrc, it scans all directories in
'packpath' for plugins under the "pack/*/start" directory. First all those
directories are added to 'runtimepath'. Then all the plugins are loaded.
See packload-two-steps for how these two steps can be useful.
In the example Vim will find "pack/foo/start/foobar/plugin/foo.vim" and adds
"~/.vim/pack/foo/start/foobar" to 'runtimepath'.
If the "foobar" plugin kicks in and sets the 'filetype' to "some", Vim will
find the syntax/some.vim file, because its directory is in 'runtimepath'.
Vim will also load ftdetect files, if there are any.
Note that the files under "pack/foo/opt" are not loaded automatically, only the
ones under "pack/foo/start". See pack-add below for how the "opt" directory
is used.
- packadd
对于位于opt文件夹下的包,需要通过packadd来添加,这个帮助手册也说明了,它只会去opt文件夹查找。
Optional plugins
pack-add
To load an optional plugin from a pack use the :packadd command:
:packadd foodebug
This searches for "pack/*/opt/foodebug" in 'packpath' and will find
~/.vim/pack/foo/opt/foodebug/plugin/debugger.vim and source it.
This could be done if some conditions are met. For example, depending on
whether Vim supports a feature or a dependency is missing.
You can also load an optional plugin at startup, by putting this command in
your .vimrc:
:packadd! foodebug
The extra "!" is so that the plugin isn't loaded if Vim was started with
--noplugin.
It is perfectly normal for a package to only have files in the "opt"
directory. You then need to load each plugin when you want to use it.
- .vimrc
所以,为了自动使能该插件,需要在.vimrc文件中添加一个对于这个opt插件的添加
packadd matchit
- script语法
vim的script帮助文档说明了其中的命令是Ex命令,并且这些命令开始的冒号是可以省略的(The ":" characters are not really needed here. You only need to use them when you type a command. In a Vim script file they can be left out),反过来说,就是添加了冒号也不会报错。
41.1 Introduction vim-script-intro script
Your first experience with Vim scripts is the vimrc file. Vim reads it when
it starts up and executes the commands. You can set options to values you
prefer. And you can use any colon command in it (commands that start with a
":"; these are sometimes referred to as Ex commands or command-line commands).
Syntax files are also Vim scripts. As are files that set options for a
specific file type. A complicated macro can be defined by a separate Vim
script file. You can think of other uses yourself.
Let's start with a simple example:
:let i = 1
:while i < 5
: echo "count is" i
: let i += 1
:endwhile
Note:
The ":" characters are not really needed here. You only need to use
them when you type a command. In a Vim script file they can be left
out. We will use them here anyway to make clear these are colon
commands and make them stand out from Normal mode commands.
Note:
You can try out the examples by yanking the lines from the text here
and executing them with :@"
vim实现中首先会跳过任意多的空白和冒号,之后如果遇到的是一个双引号则跳过整行,这意味着任意多的冒号可以在任意多的双引号之前(尽管这没有什么意义,但是是正确语法)。
static char_u *
do_one_cmd(
char_u **cmdlinep,
int sourcing,
#ifdef FEAT_EVAL
struct condstack *cstack,
#endif
char_u *(*fgetline)(int, void *, int),
void *cookie) /* argument for fgetline() */
{
///...
for (;;)
{
/*
* 1. Skip comment lines and leading white space and colons.
*/
while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':')
++ea.cmd;
/* in ex mode, an empty line works like :+ */
if (*ea.cmd == NUL && exmode_active
&& (getline_equal(fgetline, cookie, getexmodeline)
|| getline_equal(fgetline, cookie, getexline))
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
{
ea.cmd = (char_u *)"+";
ex_pressedreturn = TRUE;
}
/* ignore comment and empty lines */
if (*ea.cmd == '"')
goto doend;
if (*ea.cmd == NUL)
{
ex_pressedreturn = TRUE;
goto doend;
}
///...
}
- 验证
vim内置命令scriptnames可以显示所以执行过的脚本文件,还可以通过function来显示所有函数功能。
:scr :scriptnames
:scr[iptnames] List all sourced script names, in the order they were
first sourced. The number is used for the script ID
<SID>.
{not in Vi} {not available when compiled without the
+eval feature}
- 效果
(跟VS/VX相比)不是很智能,但是还是比内置的[[ ]] 方便一点。