vscode 下的 vim 扩展插件(vscodevim) 在 windows 下使用 wsl/ssh 远程开发时,设置的自动切换 windows 输入法无效,分析了下源码发现跟自动切换输入法相关的几个设置项,其 scope 被设置为了 machine:

https://github.com/VSCodeVim/Vim/blob/15dbe0b415f269a5be14dc74651a69b9334fba14/package.json#L1064

涉及到的设置项有:

  • vim.autoSwitchInputMethod.defaultIM
  • vim.autoSwitchInputMethod.switchIMCmd
  • vim.autoSwitchInputMethod.obtainIMCmd

翻阅 vscode 插件开发文档后了解到,当某个配置项的 scope 属性被设置为 machine 时,这意味着此配置项只在 vscode 核心具体工作的那台机器上生效,本地开发时自然是读取正常,但当进行 wsl/ssh 远程开发时,vscode 真正的核心(vscode-server)是在远程主机里工作的,本地可见的 vscode 只是个客户端或者说个空外壳,所以上述几个配置应该在远程主机中设置。

同时 vim 扩展插件的插件类型(extensionKind)被设置为了 ui 类,也就是说 vim 插件只工作 vscode UI 所在的地方,即只工作在客户端/空外壳上。

综上所述,进行远程开发时,vim 插件(其他插件也是这样)中提供的配置项,scope 属性为 machine 的配置需要在远程主机中设置,vscode 提供了这种操作的界面,如下图所示:

remote-vim-settings

需要注意的是,设置项的值应该跟在 windows 本地做开发的值是一样的,因为 vim 插件只工作在本地,只是需要从远程主机上读取这些配置(这一点设计的很奇怪)。

另外吐槽几句,vscodevim 这个插件目前是 vscode 中提供 vim 功能最完整的插件了,但是感觉 github 上的项目管理者对 PR 的审核很草率,经常引入进来新的 bug,让人头大。

阅读全文 »

这两天遇到一个 vscode 下 vim 插件的问题(另写一篇文章详述),按照 vscodevim 扩展的构建文档尝试本地调试时,发现无法编译,报如下错误:

1
2
3
正在执行任务: node_modules\.bin\gulp.cmd build-dev
bash: node_modules.bingulp.cmd: 未找到命令
终端进程“C:\msys64\usr\bin\bash.exe '--login', '-i', '-c', 'node_modules\.bin\gulp.cmd build-dev'”已终止,退出代码: 127。

可以看出来是命令找不到,但第二行的报错很奇怪,丢失了 windows 风格路径分隔符 \,查看 vscode 的终端配置发现,我把默认集成终端设置成了 msys2,那么问题很明确了,是因为 msys2 中的 bash 命令不支持 windows 风格的路径分隔符,将其解析为了转义符导致的。

在网上几番搜索皆无果,没有优雅的解决方案,还趁着这个机会认真学习了 vscode 的 launch.json, tasks.json, task provider 等文档,对问题有了一个更深入的了解。

我目前遇到的问题是因为 vscode 自带的 gulp task provider 导致的,当其发现 vscode 在 windows 下运行时,就生成 windows 风格的 gulp 命令路径参数,这在 vscode 使用 cmd 或 powershell 作为默认集成终端时没有问题,但对使用了 bash 作为 shell 的情况就会导致出错了,vscode 的 github 仓库里有几个类似、相关的,已经被关闭并锁定了的 issues:

https://github.com/microsoft/vscode/issues/35593

https://github.com/microsoft/vscode/issues/48149

https://github.com/microsoft/vscode/issues/40954

无意间从 这篇回答中找到了灵感,所以有了如下解决方案,修改 vscode 的配置文件 settings.json,在对集成终端的配置中添加一个自定义终端配置,并将其设置为默认终端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"terminal.integrated.profiles.windows": {
"bash (MINGW64-MSYS2)": {
"path": "C:\\msys64\\usr\\bin\\bash.exe",
"args": [
"--login",
"-i",
"-c",
"if [ -z \"$@\" ]; then bash; else eval \"$(cygpath \"$@\")\"; fi"
],
"env": {
"CHERE_INVOKING": "1",
"MSYSTEM": "MINGW64",
"MSYS2_PATH_TYPE": "inherit"
}
},
// other terminal profiles
// ....
},
"terminal.integrated.defaultProfile.windows": "bash (MINGW64-MSYS2)",
阅读全文 »

vspd 全称虚拟串口驱动,官方也没有给出很详细的文档,这里仅记录一些自己的理解

测试版本:vspd-v9.0,我主要用来创建虚拟串口以供测试使用

模式 Pairing

可成对得创建相互连通的虚拟 COM 口,仅能选择新的虚拟 COM 口进行创建,不能使用已存在的 COM 口

举例:
创建 COM100 与 COM101 作为 Pairing,使用串口工具打开两个 COM 口,可以互发数据

模式 Split

将一个真实 COM 串口 split 为多个虚拟 COM 口
在这种情况下,被 split 的真实 COM 口接收到的所有数据都会发送到每个 split 出来的虚拟 COM 口
反之亦然,即每个 split 出来的虚拟 COM 口接收到的所有数据,都会发送到真实 COM 口

注意,一旦设置生效,则被 split 的真实 COM 口将始终处于被占用状态,其他串口调试工具将无法再次打开它,split 出来的虚拟 COM 口则必须是新创建的,不能是已存在的 COM 口

举例:
电脑上存在一个真实 COM 口名为 COM1,将其在 Split 模式下拆分到新的 2 个虚拟 COM 口:COM100 和 COM101,当 COM1 (从外部)接收到数据时,COM100 和 COM101 也都能接收到同样的数据
反过来,当 COM100 或 COM101 接收到数据时,COM1 也将接收到同样的数据

注:
所以 COM100 和 COM101 都相当于是 COM1 的引用?
并发问题?

阅读全文 »

NAME

wireshark-filter - Wireshark display filter 显示过滤器语法手册

SYNOPSIS

1
2
3
wireshark [other options] [ -Y "display filter expression" | --display-filter "display filter expression" ]

tshark [other options] [ -Y "display filter expression" | --display-filter "display filter expression" ]

DESCRIPTION

Wireshark 和 TShark 共享一个强大的过滤引擎,有助于从数据包列表中去除“噪音”,只看到您感兴趣的数据包。如果一个数据包符合你的过滤器中表达的要求,那么它就会显示在数据包列表中。显示过滤器可让您将协议中的字段与特定值进行比较,将字段与字段进行比较,并检查指定字段或协议是否存在。

过滤器也被其他功能所使用,如统计数据的生成和数据包列表的着色(后者只对Wireshark有效)。本手册页描述了它们的语法。可以在 Wireshark 和 https://www.wireshark.org/docs/dfref/ 的显示过滤器参考中找到过滤器字段的全部参考文档。

FILTER 语法

判断一个字段或者协议是否存在

最简单的过滤器允许您检查协议或字段是否存在。如果您想查看所有包含 IP 协议的数据包,过滤器将是 ip。要查看包含 Token-Ring RIF 字段的所有数据包,请使用 tr.rif

阅读全文 »

近期工作接触到了些 linux 在 OSI 二层(数据链路层)使用 ethernet 协议收发数据包的内容,网上搜罗了一些有用的文档:

另外有一些第三方库也可以做到处理链路层数据:

下面是我对 linux man 手册 packet(7) 的翻译,虽然上面已有相关中文翻译的链接,但我个人认为有部分相关术语使用得不太合适,另外我自己再翻译一边也可以加深我个人理解。

NAME

packet - 设备层的 packet 接口

SYNOPSIS 概要

1
2
3
4
5
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */

packet_socket = socket(AF_PACKET, int socket_type, int protocol);

DESCRIPTION 描述

阅读全文 »

在 QtCreator 使用 Fakevim 可以指定读取配置文件,在配置文件中映射按键,我发现当映射 + 寄存器时(也就是系统剪切板)不生效,比如下面这行命令:

1
map <Space>yy "+yy

尝试了很多方法,比如转义:\"+yy 等都不行,网上也搜不到相关问题,下载了 QtCreator 的源码后,分析 Fakevim 插件解析配置文件的部分,发现是一个 Bug,相关代码如下:

1
2
3
4
5
6
7
// qt-creator/src/plugins/fakevim/fakevimhandler.cpp
// bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd)

// remove comment
int i = nextline.lastIndexOf('"');
if (i != -1)
nextline = nextline.remove(i, nextline.size() - i);

原来是判断 " 号是配置文件注释,将 " 号开始到结尾的部分给删除了,已经给 QtCreator 官方提了 Issue,说实话我也没想到修复这个问题的好方法。

另辟蹊径,既然要判断 " 号,而且代码里是判断最后一个 " 号的位置,那就给它加上个行内注释,让它不删除命令内容就行,比如还是上面的命令,修改后如下:

1
map <Space>yy "+yy " placehoder commend for a Fakevim parse bug

这样源码删除后面的注释后,剩下的就是原本想要执行的命令了,搞定 :)

参考并修正了其中的错误:https://www.cnblogs.com/malw/p/10542557.html

堆排序是基于完全二叉树实现的,在将一个数组调整成一个堆的时候,关键之一的是确定最后一个非叶子节点的序号,这个序号为 n/2-1n 为数组的长度。但是为什么呢?

可以分两种情况考虑:

  1. 堆的最后一个非叶子节点只有左孩子
  2. 堆的最后一个非叶子节点有左右两个孩子

完全二叉树的性质之一是:如果节点序号为 i,则它的左孩子序号为 2*i+1,右孩子序号为 2*i+2

  1. 对于 情况1 左孩子(最后一个元素)的序号为 n-1,则 n-1=2*i+1,推出 i=n/2-1
  2. 对于 情况2 左孩子(倒数第二个元素)的序号为 n-2,则 n-2=2*i+1,推出 i=(n-1)/2-1;右孩子(最后一个元素)的序号为 n-1,则 n-1=2*i+2,推出(这里跟左孩子推出的一样) i=(n-1)/2-1

很显然,当完全二叉树最后一个节点是其父节点的左孩子时,树的节点数(数组元素数)为偶数;当完全二叉树最后一个节点是其父节点的右孩子时(满二叉树),树的节点数(数组元素数)为奇数。

根据一般编程语言的特性,整数除不尽时向下取整,则若 n 为奇数时 (n-1)/2-1=n/2-1

因此对于 情况2 最后一个非叶子节点的序号也是 n/2-1

与 freedesktop.org 相关的软件

下面是一个与 freedesktop.org 相关的不完全软件列表。

你可以去我们的 Gitlab 服务查看和下载它们的代码、Bugs、提交合并请求。

freedesktop.org 本身并不每天运行这些项目:我们为自己运行项目的社区提供托管和基础设施。

All projects hosted by us are available under open-source licenses under equitable terms to all parties. These projects do not require Contributor License Agreements which assign more rights to one party than another. They may require an assertion like the Developer’s Certificate of Origin which is simply a more formal document to state that you are leally permitted to contribute under the project’s license; you do not, however, need to assign anyone rights that you do not yourself receive to others’ contributions.

桌面中间件和框架

这些项目提供了桌面的基础服务。

  • AccountsService 提供本地账户的信息。
  • D-Bus 是一个详细系统,提供了进程间和服务间通讯。
  • GeoClue 提供地理位置信息。
  • PolicyKit 是一个允许非特权应用配置和请求特权服务和接口的工具。
  • NetworkManager 允许应用发现,配置,连接有线和无线网络。
  • realmd 允许客户端发现,认证和加入网络(如 Active Directory)。
  • upower 提供了关于电源设备,如电池和充电状态的信息。
  • Zeitgeist 是一个桌面事件日志框架。

桌面规范和工具

这些规范和工具定义了跨桌面标准和互通性。

阅读全文 »

摘自 bash man 手册

字符 $ 引入了参数扩展,命令替换和算术扩展。要扩展的参数名或符号可能包含在花括号中,花括号可选的,但是可以使得要扩展的变量不会与紧随其后的字符合并,成为新的名称。

使用花括号的时候,匹配的右括号是第一个 },并且它没有被反斜杠引用或包含在一个引用的字符串中,也没有包含在一个嵌入的算术扩展,命令替换或是参数扩展中。

  • ${parameter}

    被替换为 parameter 的值。

    • 如果 parameter 是一个位置参数,并且数字多于一位时;或者当紧随 parameter 之后有不属于名称一部分的字符时,都必须加上花括号。
    • 如果 parameter 的第一个字符是一个感叹号,将引进一层间接变量。bash 使用以 parameter 的其余部分为名的变量的值作为变量的名称;接下来新的变量被扩展,它的值用在随后的替换当中,而不是使用 parameter 自身的值。这也称为 indirect expansion(间接扩展). 例外情况是下面讲到的 ${!prefix*}

下面的每种情况中,word 都要经过波浪线扩展,参数扩展,命令替换和算术扩展。如果不进行子字符串扩展,bash 测试一个没有定义或值为空的参数;忽略冒号的结果是只测试未定义的参数。

  • ${parameter:-word}

    Use Default Values(使用默认值)。如果 parameter 未定义或值为空,将替换为 word 的扩展。否则,将替换为 parameter 的值。

  • ${parameter:=word}

    Assign Default Values(赋默认值)。如果 parameter 未定义或值为空, word 的扩展将赋予 parameter. parameter 的值将被替换。位置参数和特殊参数不能用这种方式赋值。

  • ${parameter:?word}

    Display Error if Null or Unset(显示错误,如果未定义或值为空)。如果 parameter 未定义或值为空,word (或一条信息,如果 word 不存在) 的扩展将写入到标准错误;shell 如果不是交互的,则将退出。否则,parameter 的值将被替换。

  • ${parameter:+word}
    Use Alternate Value(使用可选值)。如果 parameter 未定义或值为空,不会进行替换;否则将替换为 word 扩展后的值。

  • ${parameter:offset}${parameter:offset:length}

    Substring Expansion(子字符串扩展)。扩展为 parameter 的最多 length 个字符,从 offset 指定的字符开始。

    • 如果忽略了 length,扩展为 parameter 的子字符串,从 offset 指定的字符串开始。length 和 offset 是算术表达式 (参见下面的 ARITHMETICEVALUATION 算术求值 段落)。length 必须是一个大于等于 0 的数值。
    • 如果 offset 求值结果小于 0,值将当作从 parameter 的值的末尾算起的偏移量。
    • 如果 parameter 是 @,结果是 length 个位置参数,从 offset 开始。
    • 如果 parameter 是一个数组名,以 @ 或 * 索引,结果是数组的 length 个成员,从 ${parameter[offset]} 开始。子字符串的下标是从 0 开始的,除非使用位置参数时,下标从 1 开始。
  • ${!prefix*}

    扩展为名称以 prefix 开始的变量名,以特殊变量 IFS 的第一个字符分隔。

  • ${#parameter}

    替换为 parameter 的值的长度 (字符数目)。

    • 如果 parameter 是 * 或者是 @, 替换的值是位置参数的个数。
    • 如果 parameter 是一个数组名,下标是 * 或者是 @, 替换的值是数组中元素的个数。
  • ${parameter#word}${parameter##word}

    word 被扩展为一个模式,就像路径扩展中一样。

    • 如果这个模式匹配 parameter 的值的起始,那么扩展的结果是将 parameter 扩展后的值中,最短的匹配 (``#’’ 的情况) 或者最长的匹配 (``##’’的情况) 删除的结果。
    • 如果 parameter 是 @ 或者是 *, 则模式删除操作将依次施用于每个位置参数,最后扩展为结果的列表。
    • 如果 parameter 是一个数组变量,下标是 @ 或者是 *, 模式删除将依次施用于数组中的每个成员,最后扩展为结果的列表。
  • ${parameter%word}${parameter%%word}

    word 被扩展为一个模式,就像路径扩展中一样。

    • 如果这个模式匹配 parameter 扩展后的值的尾部,那么扩展的结果是将 parameter 扩展后的值中,最短的匹配 (``%’’ 的情况) 或者最长的匹配 (``%%’’的情况) 删除的结果。
    • 如果 parameter 是 @ 或者是 *, 则模式删除操作将依次施用于每个位置参数,最后扩展为结果的列表。
    • 如果 parameter 是一个数组变量,下标是 @ 或者是 *, 模式删除将依次施用于数组中的每个成员,最后扩展为结果的列表。
  • ${parameter/pattern/string}${parameter//pattern/string}

    pattern 被扩展为一个模式,就像路径扩展中一样。parameter 被扩展,其值中最长的匹配 pattern 的内容被替换为 string。在第一种形式中,只有第一个匹配被替换。第二种形式使得 pattern 中所有匹配都被替换为 string。

    • 如果 pattern 以 # 开始,它必须匹配 parameter 扩展后值的首部。
    • 如果 pattern 以 % 开始,它必须匹配 parameter 扩展后值的尾部。
    • 如果 string 是空值,pattern 的匹配都将被删除, pattern 之后的 / 将被忽略。
    • 如果 parameter 是 @ 或者是 *, 则替换操作将依次施用于每个位置参数,最后扩展为结果的列表。
    • 如果 parameter 是一个数组变量,下标是 @ 或者是 *, 模式删除将依次施用于数组中的每个成员,最后扩展为结果的列表。

前段时间遇到个奇怪的问题,在 qtcreator 中 qDebug 语句的打印内容一直出不来,解决方法是在构建工具链设置中新增一个环境变量:QT_ASSUME_STDERR_HAS_CONSOLE=1

具体步骤(英文菜单):
点击 qtcreator 工具栏,依次点击 Tools > Options > Kits,之后选择正在使用的 Kits,滚动找到 Environment, 点击 Change 然后新增上面提到的环境变量即可。

参考链接:https://stackoverflow.com/questions/41425530/qtcreator-qdebug-messages-not-shown