星期日, 十月 24, 2021

VIM学习笔记 选择模式 (Select Mode)

选择模式,可以理解为另一种可视化模式。在选择模式下,可以对选中的文本进行快速操作。比如先高亮选中文本,然后用Backspace来删除这段文本;或者先高亮选中文本,然后用输入的内容来替换这些文本。执行操作之后,Vim将自动进入插入模式(Insert Mode)

选择模式与可视化模式的主要区别在于:在可视化模式下,可以选中文本,然后执行命令操作。也就是说,要用命令来结束可视化模式。而在选择模式下,命令仅限于Backspace(用于删除操作)和可打印的字符(用于替换操作)。因为不需要输入命令,所以操作变得更为简单,但同时也存在很多限制。

进入选择模式

在常规模式下,可以使用以下命令进入选择模式。如果已经启用'showmode'选项,那么将在屏幕底部显示相应的选择模式名称:

命令描述模式名称
gh进入字符选择模式-- SELECT --
gH进入行选择模式-- SELECT LINE --
gCTRL-H进入块选择模式-- SELECT BLOCK --

可视化模式(Visual Mode)下,可以使用Ctrl + g快捷键,进入选择模式。Vim将根据当前所处的可视化模式的类型,自动进入与之一致的字符/行/块选择模式。再次点击ctrl-G键,将返回到可视化模式。

可以使用ctrl-O命令从选择模式切换到可视化模式。

选择模式下的操作

在选择模式下移动光标比在正常模式下要困难一些。因为输入任何可打印字符和回车符,Vim就会删掉已选中的文本并进插入状态。所以要选择文本就只能使用方向键、CTRL以及功能键。

如果希望使用Shift键来扩展选择,那么需要在'keymodel'选项中包含"startsel":

:set keymodel=startsel,stopsel

如果要在选择模式下用鼠标来选择文本,需要设置以下选项:

:set selectmode=mouse

退出选择模式

使用EscCtrl-[键,可以退出选择模式。

帮助信息

:help select-mode

Ver: 2.0 | YYQ<上一篇 | 目录 下一篇>

星期五, 十月 22, 2021

VIM学习笔记 脚本-字典-实例(Script-Dictionary-Example)

可以将字典(Dictionary),理解为存储了关于键-值的成对的二元数组。以下将演示在脚本中利用字典数据结构的实例。

删除重复行

文本排序(sort)章节中,使用以下Vim内置的排序命令,可以去除文件中的重复行,同时原始行的顺序也将随之改变。对于重复的多行,将仅仅保留第一行,而其它的行将被删除。

:%sort u

创建自定义函数

以下将自定义Uniq()函数,利用字典数据结构来去除重复行,同时保留原始的行顺序。

Script-UDF-Uniq
Source code: Uniq.vim

首先,新建一个空字典"have_already_seen"用于遍历指定区域内的所有行;而不重复的行将被加入到字典"unique_lines"中。

因为字典结构不会存储键为空的项目,所以在循环语句中,将为每行内容新增前导字符'>',以确保行不为空。

函数将检查行是否已经作为键存在于字典"have_already_seen"中。如果已经存在,就忽略此行;如果不存在,则被加入字典"unique_lines"中。最后,字典"unique_lines"将仅仅包含所有唯一的行,并以原始的顺序排列;而重复的行,则会被删除。

调用自定义函数

将以上代码添加到vimrc配置文件之后,使用以下命令,可以针对整个文件执行函数:

:%call Uniq()

也可以创建快捷键,针对指定的行范围(如可视化模式下选中的行)执行函数:

vmap u :call Uniq()<CR>

Script-UDF-Uniq

Ver: 2.0 | YYQ<上一篇 | 目录 下一篇>

星期四, 九月 09, 2021

VIM学习笔记 脚本-字典(Script-Dictionary)

可以将字典(Dictionary),理解为存储了关于键-值的成对的二元数组。如果你知道了键,就能快速地查找它对应的值。

创建字典

使用以花括号包含逗号分隔的键-值列表,来创建字典。每个项目包含以冒号分隔的键和值。

let flavor = {
\ '01': 'guava',
\ '02': 'mangosteen',
\ '03': 'mango',
\ '04': 'banana',
\ '05': 'coconut',
\ '06': 'passionfruit',
\ '07': 'watermelon',
\ '08': 'papya'
}

"创建空字典
let emptydict = {}

访问字典

可以使用以方括号包围的索引编号,来访问字典的值;而更直观的方式,是使用键的名称:

let Dx = flavor['09']

如果键只包含字母、数字和下划线,那么可以使用以点标记的形式进行访问。这种类似“表名.列名”的书写形式,非常类似于数据库的记录格式,显得更简洁也更易读:

let user = {}
let user.name = 'Bram'
let user.acct = 123007

如果键不存在,那么将显示以下报错信息:

E716: Key not present in Dictionary: 09

使用get()函数来访问字典的值,第一个参数指定字典,第二个参数指定需要查找的键。如果该键存在,将返回对应的值,如果指定的键不存在,则返回0。如果指定了第三个参数,那么在指定的键不存在时,则返回此参数值。

echo get(flavor, '08')          "papya
echo get(flavor, '09')          "0
echo get(flavor, '09', 'None')  "None

新增项目

使用以下命令为新的键赋值,即可为字典新增项目:

let diagnosis = {'1':'item1'}

使用extend()函数,可以为字典新增多个项目:

call extend(diagnosis, {'2':'item2', '3':'item3'})
" '1': 'item1', '2': 'item2', '3': 'item3'

使用extend()函数,也可以合并两个字典:

let new_diagnosis = {'0':'new'}
call extend(diagnosis, new_diagnosis)
" '0': 'new', '1': 'item1', '2': 'item2', '3': 'item3'

删除项目

使用remove()函数,可以删除字典中的项目:

let removed_value = remove(flavor, '09')

当需要删除多个项目时,使用filter()函数将更加高效。 与过滤列表项目类似,您可以使用v:val和v:key进行操作:

" 删除所有以0开头键值的项目
call filter(flavor, 'v:key[0] != "0"') 
" 删除所有不包含指定内容的项目
call filter(flavor, 'v:val =~ "mango"') 
" 删除所有键与值相同的项目
call filter(diagnosis, 'v:key != v:val')

字典和列表

使用以下命令,可以获取字典中的键列表,值列表,和键-值列表:

let dict = {'key1':'value1', 'key2':'value2', 'key3':'value3'}
let keylist = keys(dict)
" ['key1', 'key2', 'key3']
let valuelist =	values(dict)
" ['value1', 'value2', 'value3']
let pairlist = items(dict)
" [['key1':'value1'], ['key2':'value2'], ['key3':'value3']]

大多数关于列表的函数,同样也适用于字典:

let is_empty =	empty(dict)           " 测试字典是否为空
let entry_count = len(dict)           " 返回字典中包含项目的总数量	
let occurrences = count(dict, str)    " 返回字典中值为str的项目的数量
let greatest = max(dict)              " 返回最大值
let least = min(dict)                 " 返回最小值

使用map()函数操作数据,可以将其中的字符串格式化为首字母大写:

let names = {'u1': 'TOM', 'u2': 'jerry', 'u3': 'alEX'}
call map( names, 'toupper(v:val[0]) . tolower(v:val[1:])' )
" {'u1': 'Tom', 'u2': 'Jerry', 'u3': 'ALex'}

关于相关函数的使用说明,请参阅列表(List)章节。

帮助信息

使用以下命令,可以查看字典相关的帮助信息:

:help Dictionary
:help Dictionary-function

函数小结
len()字典的项目总数
empty()检查字典是否为空
remove()删除字典里一或多个项目
copy()建立字典的浅备份
deepcopy()建立字典的完整备份
filter()过滤指定的字典项目
map()改变每个字典项目
max()字典项目的最大值
min()字典项目的最小值
count()计算字典里某值的出现次数

Ver: 2.0 | YYQ<上一篇 | 目录 下一篇>

星期三, 一月 20, 2021

VIM学习笔记 脚本-列表(Script-List)

列表(List),是一组由逗号分隔的项目的有序序列。它与其它编程语言中的数组(Array)概念非常相似。可以使用索引号来访问列表项目。也可以在序列的任何位置上增加或者删除项目。

请注意下文中引号后的文字为命令执行的结果,以演示各个函数的功能。

创建列表

可以将一组由逗号分隔的项目放置在方括号之内,以创建一个列表。列表中的项目索引从0开始。可以使用[n]形式,来引用特定的列表项目。

let data = [1,2,3,4,5,6,"seven"]
echo data[0]                            " 1
let data[1] = 42                        " [1,42,3,4,5,6,"seven"]
let data[2] += 99                       " [1,42,102,4,5,6,"seven"]
let data[6] .= ' samurai'               " [1,42,102,4,5,6,"seven samurai"]

使用[m:n]形式,可以引用指定范围的列表项目。

let data = [-1,0,1,2,3,4,5]
let positive = data[2:6]                 " [1,2,3,4,5]

如果忽略索引的起始位置,那么将默认从列表首个项目开始;如果忽略索引的结束位置,那么将默认至列表最后一个项目。

let middle = len(data)/2                 " middle = 3
let first_half = data[: middle-1]        " data[0 : middle-1]
echo first_half                          " [-1,0,1]
let second_half	= data[middle :]         " data[middle : len(data)-1]
echo first_half                          " [2,3,4,5]

使用range()函数,可以生成一个整数值的列表。 range(max)将生成从0到max-1的列表;range(min, max)将生成包含min和max在内的连续值列表;range(min, max, step)将从min到max,按照step指定的步长来生成列表。

let seq_of_ints = range(5)               " [0,1,2,3,4]
let seq_of_ints = range(1,5)             " [1,2,3,4,5]
let seq_of_ints = range(1,10,2)          " [1,3,5,7,9]

列表嵌套

除了数值和字符串之外,列表中也可以包含嵌套的列表。

let pow = [
\   [ 1, 0, 0, 0  ],
\   [ 1, 1, 1, 1  ],
\   [ 1, 3, 9, 27 ]
\]

echo pow[2][3]     " 27

" [2],指第3个嵌套列表
" [3],指嵌套列表中的第4个项目 

引用列表

将变量赋值为列表时,实际上是将变量指向列表;如果再次将该变量赋给其它变量,那么这两个变量都将指向同一个列表。也就是说,对于实际列表值的变更,将同时影响所有指向它的变量。

let old_suffixes = ['.c', '.h', '.py']
let new_suffixes = old_suffixes
let new_suffixes[2] = '.js'
echo old_suffixes      " ['.c', '.h', '.js']
echo new_suffixes      " ['.c', '.h', '.js']

复制列表

使用copy()函数复制列表,就可以使用不同的变量,来保存不同状态下的列表值。

let old_suffixes = ['.c', '.h', '.py']
let new_suffixes = copy(old_suffixes)
let new_suffixes[2] = '.js'
echo old_suffixes      " ['.c', '.h', '.py']
echo new_suffixes      " ['.c', '.h', '.js']

请注意,copy()函数只会复制最顶层的列表,即列表的浅备份。如果顶层列表包含嵌套列表,那么嵌套的子列表,将仅仅被作为指向实际子列表的指针被复制。也就是说,对于实际子列表的更改,将同时影响所有指向它的变量。

let pedantic_pow = copy(pow)
echo pow               " [[1, 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]
echo pedantic_pow      " [[1, 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]

let pedantic_pow[0][0] = 'vague'
echo pow               " [['vague', 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]
echo pedantic_pow      " [['vague', 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]

" also changes pow[0][0] due to shared nested list

使用deepcopy()函数,则可以复制顶层列表及其包含的嵌套列表,即列表的完整备份。

let pedantic_pow = deepcopy(pow)
echo pow               " [[1, 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]
echo pedantic_pow      " [[1, 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]

let pedantic_pow[0][0] = 'vague'
echo pow               " [[1, 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]
echo pedantic_pow      " [['vague', 0, 0, 0], [1, 1, 1, 1], [1, 3, 9, 27]]

" pow[0][0] now unaffected; no nested list is shared

拆分列表

使用split()函数,可以将字符串拆分为列表:

let words = split("one two three")          " 以空格为分隔符
echo words                                  " ['one', 'two', 'three']

let words = split("one:two three", ":")     " 以指定字符为分隔符
echo words                                  " ['one', 'two three']

合并列表

使用join()函数,可以将列表中的项目合并为字符串:

let list = ['one', 'two', 'three']
let str = join(list)                        " 使用空格连结列表项目
echo str                                    " one two three
let str = join(list, ';')                   " 使用指定字符连结列表项目
echo str                                    " one;two;three

列表长度和位置

使用以下函数,可以计算列表的长度,以及在列表中所处的位置:

let list = [1, 2, 3]
let list_length   = len(list)             " 列表的项目总数
echo list_length                          " 3
let greatest_elem = max(list)             " 列表项目的最大值
echo greatest_elem                        " 3
let least_elem    = min(list)             " 列表项目的最小值
echo least_elem                           " 1
let list_is_empty = empty(list)           " 将列表置为空
echo list_is_empty                        " 0

let week = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat','Sun']
let value_found   = index(week, 'Sun')    " 第一次出现指定值的索引位置
echo value_found                          " 0
let value_found   = index(week, 'sun')    " 如果没有找到匹配值(区分大小写)将返回-1
echo value_found                          " -1
let value_count   = count(week, 'Sun')    " 出现指定值的次数
echo value_count                          " 2

增加列表项目

call insert(list, newval)          " 在列表开头增加新项目
call insert(list, newval, idx)     " 在列表指定位置之前增加新项目
call    add(list, newval)          " 在列表末尾增加新项目

删除列表项目

call remove(list, idx)             " 删除指定位置的项目
call remove(list, from, to)        " 删除指定范围的项目

排序列表项目

let list = [3, 2, 1]
call sort(list)                   " 为列表排序
echo list                         " [1, 2, 3]
call reverse(list)                " 反转列表项目的排序
call list                         " [3, 2, 1]

过滤列表项目

使用filter({expr1}, {expr2})函数,可以对{expr1}指定的列表中的每个项目计算{expr2}表达式,以过滤掉符合指定模式的项目。

let data = [-1,0,1,2,3,4,5]
let positive = filter(copy(data), 'v:val >= 0')       " 过滤掉负数
echo positive                                         " [0,1,2,3,4,5]

let words = ['Linux', 'Unix', 'Mac']
let nnix = filter(copy(words), 'v:val !~ ".*nix"')    " 过滤包含nix的字符串
echo nnix                                             " ['Linux', 'Mac']

call filter(words, 0)                                 " 过滤掉所有项目
echo words                                            " []

修改列表项目

使用map({expr1}, {expr2})函数,可以将{expr1}指定的列表中的每个项目替换为{expr2}表达式的的计算结果。

let data = [-1,0,1,2,3,4,5]
let inc = map(copy(data), 'v:val + 1')                " 为每个成员+1
echo inc                                              " [0,1,2,3,4,5,6]

let words = ['Linux', 'Unix', 'Mac']
let cap = map(copy(words), 'toupper(v:val)')          " 将每个成员转换为大写
echo cap                                              " ['LINUX', 'UNIX', 'MAC']

连结列表

使用++=操作符,可以连结多个列表。

let activities = ['sleep', 'eat'] + ['drink']         " ['sleep', 'eat', 'drink']
let activities += ['code']                            " ['sleep', 'eat', 'drink', 'code']

请注意,操作符两侧必须均为列表。如果将列表与其它类型的数据连结,将会报错:

let activities += 'code'                              " E734: Wrong variable type for +=

常见问题

请注意,所有列表相关的函数都将修改后的列表作为返回结果,同时参数中的列表也将被修改。而通常,我们会希望返回修改后的列表,但保持原始列表不变。因此,建议使用copy()函数来复制原始列表作为参数,以避免其被修改。

let new_values = map(values, 'v:val * v:val')             " values和new_values均被修改
let new_values = map(copy(values), 'v:val * v:val')       " values保持不变

let sorted_list = reverse(sort(unsorted_list))            " unsorted_list和sorted_list均被修改
let sorted_list = reverse(sort(copy(unsorted_list)))      " unsorted_list保持不变

帮助信息

使用以下命令,可以查看列表相关的帮助信息:

:help list
:help list-functions

函数小结
len()列表的项目总数
empty()检查列表是否为空
insert()在列表某处插入项目
add()在列表后附加项目
remove()删除列表里一或多个项目
copy()建立列表的浅备份
deepcopy()建立列表的完整备份
filter()过滤指定的列表项目
map()改变每个列表项目
sort()为列表项目排序
reverse()反转列表项目的顺序
split()分割字符串成为列表
join()合并列表项目成为字符串
range()返回数值序列的列表
index()列表里某值的索引
max()列表项目的最大值
min()列表项目的最小值
count()计算列表里某值的出现次数

Ver: 2.0 | YYQ<上一篇 | 目录 下一篇>

星期四, 一月 14, 2021

VIM学习笔记 通道(channel)

假设使用以下命令,连续开启两个异步作业

:call job_start('cd ~/.vim/')
:call job_start('ls')

这些作业之间,将是相互独立的。也就是说,连续执行这两条命令,并不能进入指定目录并列示文件。第一条命令,开启一个后台作业并使用'cd'命令进入目录;第二条命令,开启另一个独立的后台作业并使用'ls'命令列示当前目录的文件。

通道概念

利用Vim内置终端功能,可以改变当前目录并列示文件:

:terminal
$ cd ~/.vim
$ ls

也就是说,terminal命令开启了一个异步作业(即shell进程),它持续等待用户的输入,并解释执行键入的shell命令。vim利用通道(channel)来与后台异步作业进行通讯。借由此机制,vim可以获取外部命令的输出和状态,并执行回调函数进行响应。而随着外部命令的结束,通道也会自动关闭。

开启通道

使用ch_open({address} [, {options}])函数,可以开启通道:

:let channel = ch_open('localhost:8765', {'callback': "MyHandler"})

在通道选项{options}中,模式"mode"规定了通讯的消息格式(即传输和读写字符串的格式)。共支持四种模式:

  • NL,利用换行符(newline)来分隔消息。使用job_start()函数启动的作业,默认使用此模式;
  • JSONjson数据交换格式。使用ch_open()函数开启的通道,默认使用json模式;
  • JS,JavaScript风格的信息格式,效率比json更高;
  • RAW,原始格式,完全由用户在回调函数中进行处理。

至于应该使用何种模式的通道,则取决于另一端程序所提供的服务。对于简单通讯可以使用 NL 模式,而复杂的服务则推荐 JSON 模式。

模式的选择,也将影响"callback"回调函数的定义。一般形式为:

func MyHandler(channel, msg)
   echo "from the handler: " . a:msg
endfunc
  • channel参数,是通道ID,即ch_open()的返回值,代表某个特定的通道;
  • msg参数,即消息内容。如果是JSON或JS模式,将会自动解码为VimL数据类型,比如嵌套的字典或列表结构等;如果是NL模式,则将其转换为去除换行符的字符串;如果是RAW模式,则保留原始信息,其中的换行符也需要用户在回调函数中自行处理。

通道交互

开启通道并与另一端的程序建立连接之后,vim可以向对方发送请求,并等待回应,以此来协同工作。

针对不同模式的通道,需要使用不同的方式来发送信息:

JSON / JSNL / RAW描述
call ch_sendexpr(channel,{expr})call ch_sendraw(channel,{string})异步发送消息
不等待响应
call ch_sendexpr(channel,{expr},
     {'callback':MyHandler})
call ch_sendraw(channel,{string},
     {'callback':'MyHandler'})
异步发送消息
指定回调函数来响应
let response =
    ch_evalexpr(channel,{expr})
let response =
    ch_evalraw(channel,{string})
同步发送消息
并等待对方响应
  • channel参数,即用于识别通道的唯一编号;
  • expr参数,指定将要发送的VimL数值或数据结构,并交由vim编码成json或js风格的字符串;
  • string参数,必须是字符串,而不能是其他复杂的VimL数据结构。

Vim实际发送的消息,为[{channel},{expr}]组成的一个二元列表;通道彼端接收消息并进行处理之后,也将由通道返回[{channel},{response}]组成的二元列表;在同一请求回应中,通道编号是相同的,据此将返回值分发到对应的回调函数。如果在发送消息时没有指定回调函数,那么将使用在ch_open()中指定的回调函数。

同步发送消息,存在阻塞的风险,但其优点是程序逻辑简单,不必使用回调函数。如果另一端的服务程序运行在本地机器,并且执行的操作耗时较短时,可以考虑使用同步消息方式。根据通道选项"timeout"键的默认设定,阻塞时间超过2000毫秒 (即2秒)时,Vim将自动终止操作。在超时或出错时,ch_evalexpr()函数将返回空字符串。

请注意,JSON和JS模式的通道也可以使用ch_sendraw()和ch_evalraw()函数,但是需要调用json_encode()和json_decode()函数来自行处理编码和解码。

通道状态

使用ch_status()函数,可以返回指定通道的状态:

:echo ch_status(channel)

状态描述
fail通道打开失败
open通道可用
buffered通道已关闭,但还有待读的数据
closed通道已关闭

使用ch_info()函数,可以返回指定通道的详细信息:

:echo ch_info(channel)

{'status': 'open', 'id': 1, 'port': 8765, 'hostname': 'localhost', 'sock_io': 'socket', 'sock_mode': 'JSON', 'sock_timeout': 2000, 'sock_status': 'open'}

函数将返回包含详细信息的字典:

描述
statusch_status()返回值
id通道号
port地址的端口号
hostname地址的机器名
sock_io"socket"
sock_mode"NL"、"RAW"、"JSON" 或 "JS"
sock_timeout以毫秒为单位的超时
sock_status"open" 或 "closed"

关闭通道

使用ch_close()函数,可以关闭指定的通道:

:call ch_close(channel)

使用套接字(socket)时,将关闭双向的套接字;使用管道 (stdin/stdout/stderr)时,将关闭所有的管道。

通道实例

在操作系统的终端中,运行Vim自带的 $VIMRUNTIME/tools/demoserver.py 演示程序,服务开始监听指定端口:

Server loop running in thread:  Thread-1
Listening on port 8765

在Vim中开启通道,连接到演示服务器:

:let channel = ch_open('localhost:8765')

此时操作系统终端中,将显示通讯开放:

=== socket opened ===

在Vim中使用以下命令,向通道彼端发送消息:

:call ch_sendexpr(channel, 'hello!')

因为没有指定回调函数,所以Vim不会显示任何回显;运行在外部终端的监听服务,将显示以下信息:

received: [1,"hello!"]
sending [1, "got it"]

在Vim中使用以下命令,向通道彼端发送消息并指定上文中定义的回调函数:

:call ch_sendexpr(channel, 'hello!', {'callback': "MyHandler"})

Vim将执行指定的回调函数,并显示以下信息:

from the handler: got it

同时运行在外部终端的监听服务,将显示以下信息:

received: [2,"hello!"]
sending [2, "got it"]

在操作系统终端中的服务程序内,输入以下命令向另一端的Vim发送消息:

["ex","echo 'hi there'"]

在Vim屏幕底部,将显示以下消息:

hi there

channel_demo

使用以下命令,可以查看关于通道的帮助信息:

:help channel

命令小结
ch_open()打开通道
ch_sendexpr()发送消息
ch_evalexpr()
ch_sendraw()
ch_evalraw()
ch_status()通道状态
ch_info()通道信息
ch_close()关闭通道

Ver: 2.0 | YYQ<上一篇 | 目录 下一篇>

星期一, 一月 04, 2021

VIM学习笔记 使用rot13加密

ROT13算法

ROT13(回转13位,英语:rotate by 13 places,有时也记为ROT-13)是一种简易的替换式密码。ROT13是一种在英文网络论坛用作隐藏八卦(spoiler)、妙句、谜题解答以及某些脏话的工具,目的是逃过版主或管理员的匆匆一瞥。ROT13被描述成“杂志字谜上下颠倒解答的Usenet点对点体”。ROT13 也是过去在古罗马开发的凯撒加密的一种变体。ROT13是它自己本身的逆反;也就是说,要还原ROT13,套用加密同样的算法即可得,故同样的操作可用再加密与解密。该算法并没有提供真正的密码学上的保全,故它不应该被套用在需要保全的用途上。它常常被当作弱加密示例的典型。

ROT13_table_with_example
Source: zh.wikipedia.org/zh-cn/ROT13

g?命令

使用 g?{motion} 命令,可以使用Rot13对{motion}跨越的文本进行编码。例如以下命令,将对当前行进行ROT13转换:

g??

使用以下命令,将对从当前行到文件末尾的文本进行ROT13转换:

:normal VGg?

使用以下命令,将对从指定行到文件末尾的文本进行ROT13转换:

:normal 10GVGg?

假设需要针对以下id属性值进行ROT13转换:

<li id="lorem">foo</li>

那么可以在g?命令中指定文本对象

g?i"

<li id="yberz">foo</li>

以下英文笑话,精华句为ROT13所隐匿:

How can you tell an extrovert from an
introvert at NSA? Va gur ryringbef,
gur rkgebireg ybbxf ng gur BGURE thl'f fubrf.

使用以下命令,透过ROT13表格转换整片文字,该笑话的解答揭露如下:

ggVGg?

Ubj pna lbh gryy na rkgebireg sebz na
vagebireg ng AFN? In the elevators,
the extrovert looks at the OTHER guy's shoes.

再次执行该命令,将重新对文本进行解密。以此类推,可以反复加密和解密整个文件。

定义以下快捷键,也可以对整个文件进行ROT13转换:

:map <F3> ggg?G

使用以下命令,可以查看相关帮助信息:

:help g?

Ver: 2.0 | YYQ<上一篇 | 目录 下一篇>

星期五, 十二月 18, 2020

The Clothed/Naked Maja

 

The Clothed/Naked Maja