Neovim - 打造一款属于自己的编辑器(一)
文章目录
- 前言(劝退)
- neovim 安装
- neovim 配置
- 配置文件位置
- 第一个 hello world 代码
- 拆分 neovim 配置
- 正式配置 neovim
- 基础配置
- 自定义键位
- Lazy 插件管理器配置
- tokyonight 插件配置
- BufferLine 插件配置
- 自动补全括号 / 引号 插件配置
前言(劝退)
neovim 是一个现代化,高扩展的 vim 编辑器 fork 版本,适合程序员打造极致高效的开发环境。
在正式开始 neovim 配置之前,我还是要劝退一下的。
很多人说使用 neovim 的都是变成高手,但我认为,能搞明白 neovim 一定是高手居多,但不一定都是顶尖的大牛,但起码技术一定不差,也正因如此,很多人使用使用 neovim 单纯是因为脑子一热,导致最后不仅耽误了手头的工作还啥都没学会。要学习neovim,建议先把 vim 的操作搞熟悉(可以全程使用 vim 的语法做出一个完整的项目,注意我说的只是语法),而 vim 学习的曲线前期有点难度,导致很多人也挂在了第一关
,所以:
如果你编程能力不足
,那么请不要碰 vim / neovim 等任何需要大量自定义的编辑器。IDEA / VsCode 就够了。如果你对 "折腾" 这件事没有太大兴趣
,那么请不要碰 vim / neovim 等任何需要大量自定义的编辑器。IDEA / VsCode 就够了。虽然也有现成的 LazyVim,但是我不建议这样做(原因后面会讲)。
neovim 安装
1)github 上搜索 neovim,在 Releases 中找到一个最近发的稳定版(https://github.com/neovim/neovim/releases),下载
安装一路 next 即可。
2)打开终端,输入 nvim test.txt 可以正常打开文本编辑器即表示安装成功
neovim 配置
配置文件位置
neovim 会在启动时加载 init.lua 文件,当我们修改了配置文件之后,重启 neovim 即可生效(虽然也可以通过 :so
实现,但是配置复杂了之后,就不好用了)
1)init.lua 文件的位置在哪?(以下路径和lua文件如果不存在,需要手动创建)
- Windows:
~/AppData/Local/nvim/init.lua(~ 表示 C:\Users\${你的用户名}\)
- Unix:
~/.config/nvim/init.lua
2)你也打开终端,输入 nvim 打开 neovim 编辑器,然后输入 :=vim.fn.stdpath("config")
来查看配置文件位置.
:
表示 vim 中的命令模式=
表示执行 lua 代码并输出结果(当然,你也可以通过:lua
执行代码,但是不会有任何输出结果)vim.fn.stdpath("config")
表示答应配置文件的完整路径
输出结果如下:
第一个 hello world 代码
1)通过 nvim init.lua
编辑配置文件,如下:
2)保存退出后,输入 nvim
重新打开 neovim,可以看到左下角的显示,如下图,表示配置生效。
拆分 neovim 配置
随着我们的配置不断增多,全写到一个 init.lua 文件中肯定是不利于维护的,因此我们将配置拆分成多个模块。
一个通用的做法如下:
1)在 init.lua 的同级目录下创建 lua 文件夹,然后再 lua 文件夹下创建 module.lua 文件,文件内容输入print("hello world")
(为了验证后续正确引入)。
2)那么就可以在 init.lua 中使用 require("module")
引入 module.lua 文件。
在 neovim 中,打开文件的命令是:e <filename>
,因此在通过 nvim 创建 module.lua 之后,直接可以通过 e: ./init.lua
打开 init.lua 文件
Ps:e 表示 edit,编辑的意思。
在 init.lua 中使用 `require(“module”),如下:
3)保存退出后,再打开 nvim,可以看到左下角 hello world
打印正常,表示上述操作步骤正确。
Ps:这里只是简单认识一下怎么拆分模块,后续的操作步骤中,会把上面演示的 module.lua 删掉(包括 init.lua 中 require 也删掉),开始正式配置 neovim。
正式配置 neovim
基础配置
1)这里我习惯将基础配置放到 ~/AppData/Local/nvim/lua/core/basic.lua
中。
同样,记得在 init.lua 中引入这个文件,如下:
2)nvim 打开 basic.lua,配置如下:
-- 显示行号
vim.opt.number = true
-- 相对行号
vim.opt.relativenumber = true-- 高亮当前光标所在行
vim.opt.cursorline = true-- 将 tab 水平制表符转化成空格
vim.opt.expandtab = true
-- tab 长度设置成4个空格
vim.opt.tabstop = 4
-- shiftwidth 设置成0,可以避免换行后回车带来的 tab 长度不一致问题
vim.opt.shiftwidth = 0-- 当 neovim 中打开的文件被其他程序修改了(例如idea),neovim 会自动加载
vim.opt.autoread = true
Ps:win 终端通过 cat 读取 lua 文件会中文乱码,可以通过
Get-Content .\lua\core\basic.lua -Encoding utf8
来查看.
自定义键位
1)这里先说一下,neovim 向下是兼容通过 vimscript 配置自定义键位的,但是我们既然使用 neovim,还是建议使用 lua 进行统一化配置。
2)自定义键位的 api:vim.keymap.set(mode, lhs, rhs, opts)
- mode:快捷键生效的模式.
- 不同模式用一个字母表示,例如 n 表示普通模式、i 表示插入模式、c 表示命令模式…
- 可以是 字符(单一模式生效,例如
n
表示在普通模式下生效),或者是 table(多模式生效,例如{'n', 'i'}
表示在普通模式和插入模式下都生效)
- lhs:表示要改哪个键位.
- 如果是普通键位,就直接写了.
- 但如果要改 Ctrl + a,就要写成
<C-a>
- 但如果要改 Alt + a,就要写成
<A-a>
- rhs:表示要改成什么样子,可以映射另一组按键,或者一个 lua 函数
- opts:是一个 table,包含了对快捷键一些额外的配置
3)案例一
vim.keymap.set("n", "<C-a>", ":lua print('hello world')<CR>", { silent = true })
- 在 normal 模式下生效.
- 按下
Ctrl + a
后,会打印 hello world,其中<CR>
表示回车 - silent = true 表示让快捷键 “静默执行”,不显示执行过程中的命令或提示信息
演示如下:
然后按下 Ctrl + a
,效果如下:
4)案例二:如果想让快捷键在 插入模式 下也生效.
错误的写法如下(有坑):
vim.keymap.set({"n", "i"}, "<C-a>", ":lua print('hello world')<CR>", { silent = true })
真的可以这样么?思考一下,因为我们在插入模式下,直接按下 <C-a>
,他会替换成 ":lua print('hello world')<CR>"
,相当于直接把这段话直接写下来了(模拟键盘输入:lua print('hello world')<CR>
的场景),如下:
正确的写法如下:
vim.keymap.set({"n", "i"}, "<C-a>", "<Cmd>lua print('hello world')<CR>", { silent = true })
<Cmd>
并不是一个具体的按键,只表示进入命令模式。
此时你在 insert模式 按下 Ctrl + a
虽然是正确的,但是看不到效果,因为在默认 neovim 会在右下加固定显示你当前的模式,不过你也可以通过 :lua vim.opt.showmode = false
关闭他,然后在 insert 模式下按下 Ctrl + a
就可以看到效果了
5)rhs 也可以是一个函数,例如如下
vim.keymap.set("n", "<C-a>", function ()print("hello world")
end, { silent = true})
这里写的是 lua 中的匿名函数,使用 end 表示结尾
6 )leader key
可以理解成在配置中定义了一个叫做 <leader>
的变量,实现复用效果。
例如如下,设置 leader key 为 空格,当我在 normal 模式下按下 空格 + a + a
,就会打印 cyk 字符串。
vim.g.mapleader = " "
vim.keymap.set("n", "<leader>aa", ":lua print('cyk')<CR>", { silent = true})
7)正式配置,创建 ~/AppData/Local/nvim/lua/core/keymap.lua
文件,如下(这里是我自己习惯的):
vim.keymap.set("i", "jk", "<esc>", { silent = true })vim.keymap.set("n", "L", "$", {silent = true})
vim.keymap.set("v", "L", "$", {silent = true})vim.keymap.set("n", "H", "^", {silent = true})
vim.keymap.set("v", "H", "^", {silent = true})
最后在 init.lua 中引入,如下:
require("core.keymap")
Lazy 插件管理器配置
1)neovim 的插件一般都需要从 github 上手动 clone 并在 neovim 中引用。但是随着插件的逐渐增多,这种方式会变得非常繁琐,这就需要使用插件管理器来自动化这个过程。我使用 lazy 插件管理器进行配置。
lazy.nvim 是 Neovim 的一款现代插件管理器,主打的是"懒加载"理念:只有当我使用某个插件时才加载他,从而极大的提升启动性能。
lazy.nvim 会读取 ~/AppData/Local/nvim/plugins/
目录下的所有 lua 插件配置文件。常见的写法如下:
return {"插件名", -- 如 "nvim-treesitter/nvim-treesitter"name = "别名", -- 可选,为插件指定别名event = "VeryLazy", -- 懒加载触发时机,支持多种事件cmd = "命令名", -- 使用命令时加载ft = "lua", -- 打开某种文件类型时加载keys = {...}, -- 使用某些快捷键时加载opts = {...}, -- 插件的配置(直接传入插件的 `setup` 或 `opts`)config = function() ... end, -- 更复杂的配置dependencies = {...}, -- 插件依赖
}
每项具体如何编写,会在后续的使用中讲到。
2)首先需要安装 git 和 nerd font。git 就不多说了,这里主要讲一下 nerd font(https://www.nerdfonts.com/font-downloads)
Ps:如果不安装字体,将来很多符号无法显示。
这里建议使用 JetBrainsMono Nerd Font
下载后解压到你常用的目录即可。
3)在 neovim 配置中自动安装和加载插件管理器逻辑。
创建 ~/AppData/Local/nvim/lua/core/lazy.lua
文件,内容如下:
-- 构造 lazy.nvim 的安装路径
-- vim.fn.stdpath("data") 表示返回 neovim 的数据目录,例如 win 是 ~/AppData/Local/nvim-data;linux/mac 是 ~/.local/share/nvim
-- .. 是 lua 用来拼接字符串的,
-- win 最后拼接成 ~/AppData/Local/nvim-data/lazy/lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"-- 如果 lazypath 不存在(lazy.nvim 未安装),就执行内部逻辑
if not vim.uv.fs_stat(lazypath) then-- 把 lazy.nvim 下载到 lazypath 目录vim.fn.system({"git","clone","--filter=blob:none","https://github.com/folke/lazy.nvim.git","--branch=stable",lazypath})
end-- 把 lazy.nvim 加入到 neovim 的运行时路径(runtimepath)的最前面
-- 这样才能使用 require("lazy") 正确加载插件管理器
-- 此处的 : 表示 lua 中的方法调用(表示传入一个方法)
vim.opt.rtp:prepend(lazypath)-- 加载 lazy.nvim 插件管理器,并调用 setup 函数
-- 传入 {} 空表,表示还没有配置任何插件,后续可以加
require("lazy").setup({})
保存后,记得在 init.lua 中引入,如下:
require("core.lazy")
保存退出后重新打开 neovim,你会发现卡住了,这是因为正在执行刚刚写的命令(neovim 是单线程的,会阻塞主线程)。
4)打开 neovim,然后输入 “:Lazy”,就可以看到一个面板如下:
例如按下 Shift + p
就可以看到插件的一些启动时的性能情况
面板上其他选项的介绍:
- Install:用来安装插件的,相当于运行
:Lazy install
,只安装在 lazy.nvim 中声明的,并且还没有下载的插件。不会更新已有的插件 - Update:更新插件,相当于运行
:Lazy Update
,他会执行 git pull 来拉取所有插件的最新版本 - Sync:同步插件状态(安装缺失的插件 + 更新已安装的插件 + 清理不在配置中的插件 + 构建插件),相当于执行
:Lazy sync
,通常用来保证插件和配置完全一致 - Clean:清理插件,相当于执行
:Lazy clean
,用来删除配置中不再引用的插件 - Check:检查插件状态,相当于执行
:Lazy check
,用来删除配置中不再引用的插件 - Log:查看插件管理器中日志的输出,主要调试用的
- Restore:恢复快照,从 snapshot 文件中恢复插件状态,回滚版本(需要提前使用
Lazy snapshot
创建快照) - Profile:性能分析,分析各个插件加载时的性能情况
- Debug:调试 lazy.nvim 插件管理器的自身行为,会打开一个窗口输出插件加载时的详细信息(哪些插件怎么加载的、懒加载生效情况、报错信息、路径、加载顺序等),适合在插件不工作,配置失效、性能分析时使用
tokyonight 插件配置
1)如下配置,会让 neovim 自动读取 lua/plugins 目录下的文件,用来对插件进行配置。
require("lazy").setup({spec = {{ import = "plugins" }}
})
然后创建 ~/AppData/Local/nvim/lua/plugins
文件夹,之后在这个此目录下,每配置一个插件就是一个 lua 文件(这种写法看起来直观)。
此时使用 nvim 可能会报错,不过不用管,这是因为 plugins 目录下还没有任何插件。
2)安装 tokyonight 主题
创建 ~/AppData/Local/nvim/lua/plugins/tokyonight.lua
文件,内容如下(从 tokyonight 的 github 上就可以看到怎么配置):
return {-- 这里写主题的 github 链接-- 但是由于插件基本都来自github,因此 lazy 会自动补全前缀 "https://github.com/",因此插件的前缀就不用写了"folke/tokyonight.nvim"
}
保存退出后重新打开,就可以看到 lazy 就直接开始帮我们安装了,然后输入 :colorscheme tokyonight
,回车后就可以看到效果了
3)如果我们再重新打开 neovim 的时候就会发现,还需要继续手动让主题生效,为了解决这个问题,可以重写 tokyonight 的 config 项,如下:
return {-- 这里写主题的 github 链接-- 但是由于插件基本都来自github,因此 lazy 会自动补全前缀 "https://github.com/",因此插件的前缀就不用写了"folke/tokyonight.nvim",-- 可以通过此配置项更换成 tokyonight 的浅色主题opts = {style = "day"},-- 下面的 config 本来是 lazy 默认配置好的,但是为了能在插件启动时自定义一些东西(比如启动时就加载好主题),可以重写此配置-- 这个方法的第一个参数几乎用不上,opts 就是上一个配置项config = function (_, opts)require("tokyonight").setup(opts) -- 这一步是 lazy 给我们自动配置好的,这里再写一遍主要是因为我们自己手动重写了此函数vim.cmd("colorscheme tokyonight") -- 执行这个命令end
}
Ps:大多数情况,是不用手动编写 config 的,除非在 lazy 默认加载之外,还有些别的操作。
4)这里你可能会有一个疑问,为什么一定要把加载主题的配置写到 config 中,而不写外部去加载?
因为切换主题这个命令,必须要在插件加载完成之后才能执行。
例如如下,我这样写,就是会报 “找不到主题的错误”。
原因:lazy.nvim 是异步懒加载插件的(读取所有的插件完之后,再统一加载),而 vim.cmd("colorscheme tokyonight")
这行代码在 tokyonight 插件真正被加载之前,就被执行了,所以就会报错 E185: Cannot find color scheme 'tokyonight'
BufferLine 插件配置
默认情况下,所有的 buffer 都是隐藏的,通过使用 bufferline 插件,可以使所有的 buffer 以类似浏览器标签页的方式呈现在页面的最上方。
1)首先创建 ~/AppData/Local/nvim/lua/plugins/bufferline.lua
文件,内容如下:
return {"akinsho/bufferline.nvim",-- 此插件必须手动指定一下 opts 才会进行 setupopts = {}
}
2)使用 neovim 随便打开一个文件,例如 nvim aaa
打开文件 aaa,就可以看到效果如下:
再使用 e bbb
编辑一个新文件 bbb,都是可以看到 tab 的
3)可以通过 :BufferLineCyclePrev
前往上一个 tab,使用 :BufferLineCyclePrev
前往下一个 tab… 但是这样太麻烦了
但是我们使用的使 neovim 啊,用的就是的自定义,当然这里还有一种更强的自定方式,就是直接在插件上配置 keys 来自定义键位,例如如下:(我这样配置主要是为了减少和 IDEA 相关操作迁移的成本)
return {"akinsho/bufferline.nvim",-- 此插件必须手动指定一下 opts 才会进行 setupopts = {},keys = {{ "<leader>bn", ":BufferLineCycleNext<CR>", silent = true },{ "<leader>bo", ":BufferLineCloseOthers<CR>", silent = true },{ "<leader>bp", ":BufferLineCyclePrev<CR>", silent = true },{ "<leader>bd", ":bdelete<CR>", silent = true },{ "<leader>bh", ":BufferLinePick<CR>", silent = true },},
}
Ps:keys 中配置的键位默认就是在 normal 模式中生效,不用手动指定 mode
4)此处重新打开 nvim 会发现 tab 不见了?这里涉及到一个高级特性就是 懒加载,实际上我们配置了 keys 他的实际含义是开启懒加载,只有在按下自定义 keys 中的键位时开始加载
。
为什么要会这样设计呢?因为 neovim 在启动时会加载所有插件,一旦插件变多了,neovim 的打开速度会越来越慢,因此就设计成在 neovim 启动后进入主页用不上的插件就先不加载,只有用到这个插件的时候再加载。而 keys 就是启动懒加载开关的其中之一(还有的后续会讲到)
当然对于 bufferline 显示 tab 这种在启动后就会用到的,我们还是希望他不要懒加载,因此可以手动设置 lazy 属性为 false,如下:
return {"akinsho/bufferline.nvim",-- 此插件必须手动指定一下 opts 才会进行 setupopts = {},keys = {{ "<leader>bn", ":BufferLineCycleNext<CR>", silent = true },{ "<leader>bo", ":BufferLineCloseOthers<CR>", silent = true },{ "<leader>bp", ":BufferLineCyclePrev<CR>", silent = true },{ "<leader>bd", ":bdelete<CR>", silent = true },{ "<leader>bh", ":BufferLinePick<CR>", silent = true },},lazy = false
}
5)目前的 bufferline 配置出来还是有点丑的,因为 icon 图标,因此这里还需要一个插件给 tab 显示小图标。
但是由于这个插件只是辅助于 bufferline 的,因此没有必要单独在 plugins 下创建一个 lua 文件,可以通过 lazy 提供的 dependencies 属性实现,如下:
return {"akinsho/bufferline.nvim",dependencies = {"nvim-tree/nvim-web-devicons"},-- 此插件必须手动指定一下 opts 才会进行 setupopts = {},keys = {{ "<leader>bn", ":BufferLineCycleNext<CR>", silent = true },{ "<leader>bo", ":BufferLineCloseOthers<CR>", silent = true },{ "<leader>bp", ":BufferLineCyclePrev<CR>", silent = true },{ "<leader>bd", ":bdelete<CR>", silent = true },{ "<leader>bh", ":BufferLinePick<CR>", silent = true },},lazy = false
}
保存后重新进入,效果如下:
自动补全括号 / 引号 插件配置
这个见名思意,输入 {
,自动补全 }
,其他的也同理。
如果删除 {
也会自动把配对的 }
删除,其他也同理。
这时候我们可以思考一个关于优化的问题,这个插件在 neovim 启动的时候真的需要加载么么?并不需要,因为他不涉及 ui 的渲染,并且 normal 模式下也不会用到,因此我们希望他进入 insert 模式下才需要使用到,此时就可以使用 event 属性进行懒加载
,如下:
return {"windwp/nvim-autopairs",event = "InsertEnter", -- 仅在 insert 模式才加载此插件opts = {}
}
1)那么重新进入 neovim,并输入 :Lazy
可以看到 nvim-autopairs 并没有被加载。
2)当进入 insert 的模式之后,再查看就加载了,说明懒加载配置成功。
Ps:有的插件可以懒加载,但是是在 normal 模式下就使用的,然而已进入 neovim 就是 normal 模式,类似这种你不清楚什么时候进行懒加载的情况,就可以配置成
event = VeryLazy
,这也是 lazy 插件管理器提供的一种方式。
相关文章:

Neovim - 打造一款属于自己的编辑器(一)
文章目录 前言(劝退)neovim 安装neovim 配置配置文件位置第一个 hello world 代码拆分 neovim 配置正式配置 neovim基础配置自定义键位Lazy 插件管理器配置tokyonight 插件配置BufferLine 插件配置自动补全括号 / 引号 插件配置 前言(劝退&am…...

RAG检索系统的两大核心利器——Embedding模型和Rerank模型
在RAG系统中,有两个非常重要的模型一个是Embedding模型,另一个则是Rerank模型;这两个模型在RAG中扮演着重要角色。 Embedding模型的作用是把数据向量化,通过降维的方式,使得可以通过欧式距离,余弦函数等计算…...

CLion社区免费后,使用CLion开发STM32相关工具资源汇总与入门教程
Clion下载与配置 Clion推出社区免费,就是需要注册一个账号使用,大家就不用去找破解版版本了,jetbrains家的IDEA用过的都说好,这里嵌入式领域也推荐使用。 CLion官网下载地址 安装没有什么特别,下一步就好。 启动登录…...

第21讲、Odoo 18 配置机制详解
Odoo 18 配置机制详解:res.config.settings 与 ir.config_parameter 原理与实战指南 在现代企业信息化系统中,灵活且可维护的系统参数配置是模块开发的核心能力之一。Odoo 作为一款高度模块化的企业管理软件,其参数配置机制主要依赖于两个关…...
LinkedList、Vector、Set
LinkedList 基本概念 LinkedList 是一个双向链表的实现类,它实现了 List、Deque、Queue 和 Cloneable 接口,底层使用双向链表结构,适合频繁插入和删除操作。 主要特点 有序,可重复。 查询速度较慢,插入/删除速度较…...
SQL 基础入门
SQL 基础入门 SQL(全称 Structured Query Language,结构化查询语言)是用于操作关系型数据库的标准语言,主要用于数据的查询、新增、修改和删除。本文面向初学者,介绍 SQL 的基础概念和核心操作。 1. 常见的 SQL 数据…...
GitHub 趋势日报 (2025年06月05日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 1472 onlook 991 HowToCook 752 ChinaTextbook 649 quarkdown 451 scrapy 324 age…...
基于Flask框架的前后端分离项目开发流程是怎样的?
基于Flask框架的前后端分离项目开发流程可分为需求分析、架构设计、并行开发、集成测试和部署上线五个阶段。以下是详细步骤和技术要点: 一、需求分析与规划 1. 明确项目边界 功能范围:确定核心功能(如用户认证、数据管理、支付流程&#…...
Delphi SetFileSecurity 设置安全描述符
在Delphi中,使用Windows API函数SetFileSecurity来设置文件或目录的安全描述符时,你需要正确地构建一个安全描述符(SECURITY_DESCRIPTOR结构)。这个过程涉及到几个步骤,包括创建或修改安全描述符、设置访问控制列表&am…...
rec_pphgnetv2完整代码学习(二)
六、TheseusLayer PaddleOCRv5 中的 TheseusLayer 深度解析 TheseusLayer 是 PaddleOCRv5 中 rec_pphgnetv2 模型的核心网络抽象层,提供了强大的网络结构调整和特征提取能力。以下是对其代码的详细解读: 1. 整体设计思想 核心概念: 网络…...

【计算机网络】Linux下简单的TCP服务器(超详细)
服务端 创建套接字 💻我们将TCP服务器封装成一个类,当我们定义出一个服务器对象后需要马上对服务器进行初始化,而初始化TCP服务器要做的第一件事就是创建套接字。 TCP服务器在调用socket函数创建套接字时,参数设置如下࿱…...
go中的接口返回设计思想
go中的接口返回设计思想 前言 在学习AI编码过程中,产生了类似以下结构的代码 : type MQClient interface {PublishMessage(queue string, message interface{}) error...... } ... type RabbitMQClient struct {conn *amqp.Connectionchannel *amqp.C…...

最新Spring Security实战教程(十七)企业级安全方案设计 - 多因素认证(MFA)实现
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Micro麦可乐的博客 🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战 🌺《RabbitMQ》…...

html+css+js趣味小游戏~Cookie Clicker放置休闲(附源码)
下面是一个简单的记忆卡片配对游戏的完整代码,使用HTML、CSS和JavaScript实现: html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"wid…...
宝塔面板安装nodejs后,通过node -v获取不到版本号,报错node: command not found
如果在 宝塔面板 安装了 Node.js,但运行 node -v 或 npm -v 时提示 command not found,通常是因为 Node.js 的路径未正确添加到系统环境变量。以下是解决方法: 1. 确认 Node.js 是否安装成功 (1)检查宝塔面板的 Node.…...

SDC命令详解:使用set_propagated_clock命令进行约束
相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html?spm1001.2014.3001.5482 目录 指定端口列表/集合 简单使用 注意事项 传播时钟是在进行了时钟树综合后,使用set_propagated_clock命令可以将一个理想时钟转换为传播时钟&#x…...

win32相关(消息Hook)
消息Hook 要想实现消息Hook需要使用到三个相关的Api SetWindowsHookEx // 设置钩子CallNextHookEx // 将钩子信息传递到当前钩子链中的下一个子程序UnhookWindowsHookEx // 卸载钩子 我们编写的消息钩子需要将设置钩子的函数写到dll里面,当钩住一个线程后ÿ…...
vue3单独封装表单校验函数
1.在页面中建一个.ts文件 import { useI18n } from /hooks/web/useI18n import { FormItemRule } from element-plusconst { t } useI18n()interface LengthRange {min: numbermax: numbermessage?: string } //必输项校验 export const useValidator () > {const requi…...

mysql 页的理解和实际分析
目录 页(Page)是 Innodb 存储引擎用于管理数据的最小磁盘单位B树的一般高度记录在页中的存储 innodb ibd文件innodb 页类型分析ibd文件查看数据表的行格式查看ibd文件 分析 ibd的第4个页:B-tree Node类型先分析File Header(38字节-描述页信息…...
分享一道力扣
刚刚笔试遇到的。好像很简单,但又不容易写的 611 有效三角形 def triangleNumber(self, nums):count 0nums.sort()for i in range(len(nums) - 2):k i 2for j in range(i 1, len(nums) - 1):if nums[i] 0:breakwhile k < len(nums) and nums[i] nums[j] &g…...
青少年编程与数学 01-011 系统软件简介 06 Android操作系统
青少年编程与数学 01-011 系统软件简介 06 Android操作系统 一、历史发展二、核心架构1. Linux 内核层 (Linux Kernel)2. 硬件抽象层 (Hardware Abstraction Layer - HAL)3. Native 层 (Native Libraries & Android Runtime)4. Java API 框架层 (Java Framework Layer)5. 应…...

构建 MCP 服务器:第 2 部分 — 使用资源模板扩展资源
该图像是使用 AI 图像创建程序创建的。 这个故事是在多位人工智能助手的帮助下写成的。 这是构建MCP 服务器教程(共四部分)的第二部分。在第一部分中,我们使用基本资源创建了第一个 MCP 服务器。现在,我们将使用资源模板扩展服务…...

【算法设计与分析】实验——汽车加油问题, 删数问题(算法实现:代码,测试用例,结果分析,算法思路分析,总结)
说明:博主是大学生,有一门课是算法设计与分析,这是博主记录课程实验报告的内容,题目是老师给的,其他内容和代码均为原创,可以参考学习,转载和搬运需评论吱声并注明出处哦。 4-1算法实现题 汽车…...
Ubuntu2404 下搭建 Zephyr 开发环境
1. 系统要求 操作系统:Ubuntu2404(64位)磁盘空间:至少 8GB 可用空间(Zephyr 及其工具链较大) 2. 安装必要工具 Tool Min. Version CMake 3.20.5 Python 3.10 Devicetree compiler 1.4.6 2.1 安装系…...
现代C++特性(一):基本数据类型扩展
文章目录 基础数据类型long long (C 11)numeric_limits()获取当前数据类型的最值warning C4309: “”: 截断常量值新字符类型char16_t和char32_tWindows编程常用字符类型wchar_tchar8_t (C 20) 基础数据类型 C中的基本类型是构建其他数据类型的基础,常见的基础类型…...

【C++进阶篇】C++11新特性(下篇)
C函数式编程黑魔法:Lambda与包装器实战全解析 一. lambda表达式1.1 仿函数使用1.2 lambda表达式的语法1.3 lambda表达式使用1.3.1 传值和传引用捕捉1.3.2 隐式捕捉1.3.3 混合捕捉 1.4 lambda表达式原理1.5 lambda优点及建议 二. 包装器2.1 function2.2 bind绑定 三.…...

全生命周期的智慧城市管理
前言 全生命周期的智慧城市管理。未来,城市将在 实现从基础设施建设、日常运营到数据管理的 全生命周期统筹。这将避免过去智慧城市建设 中出现的“碎片化”问题,实现资源的高效配 置和项目的协调发展。城市管理者将运用先进 的信息技术,如物…...

echarts柱状图实现动态展示时报错
echarts柱状图实现动态展示时报错 1、问题: 在使用Echarts柱状图时,当数据量过多,x轴展示不下的时候,可以使用dataZoom实现动态展示。如下图所示: 但是当鼠标放在图上面滚动滚轮时或拖动滚动条时会报错,…...
Redis故障转移
概述 本文主要讲述了Redis故障转移的原理及过程,可与「Redis高可用架构」文章一同阅读,可更好理解相关内容,及整个Redis高可用架构的实现原理。 Leader 选举 哨兵首先进入 WATI_START 状态进行准备,等待哨兵成为哨兵集群的 Leade…...
STM32学习笔记:定时器(TIM)原理与应用(详解篇)
前言 定时器是STM32微控制器中最重要且最常用的外设之一,它不仅能提供精确的定时功能,还能实现PWM输出、输入捕获、编码器接口等多种功能。本文将全面介绍STM32的通用定时器,包括其工作原理、配置方法和典型应用。 一、STM32定时器概述 定…...