免责声明 - 我是使用 Rust 的新手,也是使用 Linux(Ubuntu) 和 Vim(Neovim) 的新手。 我写了一个 rust crate,叫做 bins_rust,它使用 rpc 在 Neovim 中打印是否是 bin day。
在 nvim 中运行
:BinDay
命令,它应该打印,无论是 bin day 还是表情符号。
注意。这只适用于我的机器,同时在 bins_rust 目录中工作,但不适用于其他项目。
看到下面-
E475: Invalid argument: Channel doesn't exist
不清楚此警告的含义,或如何诊断和修复。请帮助。
以下文档没有提到 Channel,就像我的错误消息一样。 https://neovim.io/doc/user/message.html#%3Amessages
Plug 'murpjack/bins_rust'
cd ~/.config/nvim/vim-plug/bins_rust
cargo build --release
:source $MYVIMRC
:BinDay
在 nvim 中注册了一个名为
:BinDay
的命令
一个 rpc 通道 似乎 被创建。 (通过在单独的命令中记录 id 来断言)
通过运行
cargo build --release
创建的可执行文件 - 名为 bins_rust - 存在于
vim-plug/bins_rust 目录,并且 seemingly 在 Bash 中运行。
src/main.rs
extern crate neovim_lib;
use neovim_lib::{Neovim, NeovimApi, Session};
use serde_derive::{Deserialize, Serialize};
use std::time::{Duration, SystemTime};
fn main() {
let mut event_handler = EventHandler::new();
event_handler.recv();
}
enum Messages {
Show,
Unknown(String),
}
impl From<String> for Messages {
fn from(event: String) -> Self {
match &event[..] {
"show" => Messages::Show,
_ => Messages::Unknown(event),
}
}
}
struct EventHandler {
nvim: Neovim,
bin_day: String,
}
impl EventHandler {
fn new() -> EventHandler {
let session = Session::new_parent().unwrap();
let nvim = Neovim::new(session);
let bin_day = BinDay::print();
EventHandler { nvim, bin_day }
}
fn recv(&mut self) {
let receiver = self.nvim.session.start_event_loop_channel();
for (event, _values) in receiver {
match Messages::from(event) {
Messages::Show => {
let print = &self.bin_day;
self.nvim.command(&format!("echo \"{}\"", print)).unwrap();
}
// Handle anything else
Messages::Unknown(event) => {
self.nvim
.command(&format!("echo \"Unknown command: {}\"", event))
.unwrap();
}
}
}
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
struct BinDay {
date: u128,
bins: Vec<BinType>,
}
impl BinDay {
fn bins_to_icons(&self) -> String {
self.bins
.iter()
.map(|bin_type| String::from(BinType::to_icon(bin_type)))
.reduce(|cur: String, nxt| cur + &nxt)
.unwrap()
}
fn is_near(next_date: u128) -> bool {
let day_secs = Duration::new(((1000 * 60) * 60) * 24, 0); // 86400000;
match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(now) => {
// TODO: today_start should == today at 12am
// TODO: tomorrow_end should == tomorrow at 11.59pm
match (now.checked_sub(day_secs), now.checked_add(day_secs * 2)) {
(Some(today_start), Some(tomorrow_end)) => {
let nexty = Duration::from_millis(next_date.try_into().unwrap());
(today_start..tomorrow_end).contains(&nexty)
}
_ => false,
}
}
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
}
}
fn from_value(ab: &serde_json::Value) -> Option<BinDay> {
match (ab["date"].as_str(), ab["bins"].as_array()) {
(Some(date_str), Some(raw_bins)) => Some(BinDay {
date: date_str.parse::<u128>().unwrap(),
bins: raw_bins
.iter()
.map(|raw_bin| BinType::from_str(raw_bin.as_str().unwrap()))
.collect::<Vec<BinType>>(),
}),
_ => None,
}
}
fn print() -> String {
// TODO: Remove unwrap & handle errors -- Implement and_then for serde_json::Results
let bin_str = std::fs::read_to_string("./bins.json").unwrap();
let bin_day = serde_json::from_str::<serde_json::Value>(&bin_str)
.unwrap()
.as_array()
.unwrap()
.iter()
.find_map(|raw_day| match raw_day["date"].as_str() {
Some(date_str) => {
let date = date_str.parse::<u128>().unwrap();
if BinDay::is_near(date) {
return BinDay::from_value(raw_day);
} else {
return None;
}
}
_ => None,
});
match bin_day {
Some(today) => {
let icons = BinDay::bins_to_icons(&today);
return format!("{} {}", String::from("Bin day!"), icons);
}
_ => format!("Keep calm. It's not bin day today or tomorrow"),
}
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
enum BinType {
Biodegradable,
Landfill,
Recyclable,
NoBin,
}
impl BinType {
fn to_icon(&self) -> &str {
match self {
BinType::Recyclable => "♻️ ",
BinType::Biodegradable => "💩",
BinType::Landfill => "🗑",
BinType::NoBin => "",
}
}
fn from_str(bin_str: &str) -> BinType {
match bin_str {
"recycling" => BinType::Recyclable,
"food and garden waste" => BinType::Biodegradable,
"rubbish" => BinType::Landfill,
_ => BinType::NoBin,
}
}
}
Vimrc文件:
" Both , and \ act as leader
let mapleader = ','
map \ <Leader>
set nocompatible
if !exists('g:syntax_on')
syntax enable
endif
" Format
set encoding=utf8
set nonumber
set nowrap
" Indent
filetype plugin indent on
set tabstop=2
set shiftwidth=2
set expandtab
" Mouse can scroll
set mouse=a
" conceallevels
" 0 - No concealed characters
" 1 - Replace hidden for special characters
" 2 - No hidden characters, unless substitute available
" 3 - No hidden characters, regardless of settings
set conceallevel=2
" Allow embedded script highlighting
let g:vimsyn_embed= 'l'
let g:loaded_perl_provider = 0
let $FZF_DEFAULT_COMMAND='find . \! \( -type d \) \! -type d \! -name ''*.tags'' -printf ''%P\n'''
" Plugins
let plugins_dir = '~/.config/nvim/vim-plug'
call plug#begin(expand(plugins_dir))
Plug 'junegunn/fzf'
Plug 'junegunn/fzf.vim'
Plug 'tpope/vim-surround'
Plug 'tpope/vim-obsession'
" File tree
Plug 'scrooloose/nerdtree'
Plug 'ryanoasis/vim-devicons'
Plug 'tiagofumo/vim-nerdtree-syntax-highlight'
Plug 'vim-scripts/vim-nerdtree_plugin_open'
" Language
Plug 'sheerun/vim-polyglot'
Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'neoclide/coc-highlight'
Plug 'elm-tooling/elm-language-server'
Plug 'christoomey/vim-tmux-navigator'
" Git
Plug 'tpope/vim-fugitive'
Plug 'jreybert/vimagit'
Plug 'zivyangll/git-blame.vim'
Plug 'Xuyuanp/nerdtree-git-plugin'
" Style
Plug 'bluz71/vim-moonfly-colors'
Plug 'itchyny/lightline.vim'
" Experimental
Plug 'murpjack/bins_rust'
call plug#end()
" On startup
autocmd VimEnter * edit ~/.bashrc
autocmd VimEnter * edit ~/.bash_git_shortcuts
autocmd VimEnter * edit ~/.tmux.conf
autocmd VimEnter * edit $MYVIMRC
if (has("termguicolors"))
set termguicolors
endif
" colorscheme absent-contrast
colorscheme moonfly
" lightline
set laststatus=2
set noshowmode
let g:lightline = {
\ 'colorscheme': 'wombat',
\ 'active': {
\ 'right': [ [ 'lineinfo' ],
\ [ 'percent' ],
\ [ 'modified' ],
\ [ 'currentTime' ]
\ ]
\ },
\ 'component_function': {
\ 'currentTime': 'CurrentTime'
\ },
\ }
function! CurrentTime()
return strftime("%H:%M")
endfunction
let g:unite_force_overwrite_statusline = 0
let g:vimfiler_force_overwrite_statusline = 0
let g:vimshell_force_overwrite_statusline = 0
" Re-source nvim
nnoremap <Leader>sr :source $MYVIMRC<CR>
" Search recently-used history
nmap <C-c> :History:<space><CR>
" Search all available nvim commands
nmap <Leader>c :Commands<CR>
" See all open buffers
nnoremap <Leader><Space> :Buf<CR>
tnoremap <Leader><Space> <C-\><C-n>:Buf<CR>
" Search in home or present directory
nmap <C-l> :Files $HOME<CR>
nmap <C-p> :Files<CR>
" Use arrows to resize buffers
nnoremap <Down> :resize +2<CR>
nnoremap <Up> :resize -2<CR>
nnoremap <Right> :vertical resize +2<CR>
nnoremap <Left> :vertical resize -2<CR>
" Resize buffers quickly
nnoremap <C-Down> :resize +20<CR>
nnoremap <C-Up> :resize -20<CR>
nnoremap <C-Right> :vertical resize +20<CR>
nnoremap <C-Left> :vertical resize -20<CR>
" Faster scrolling
nnoremap <C-d> 20<C-e>
nnoremap <C-u> 20<C-y>
" Exit terminal mode
tmap <C-w> <C-\><C-n><C-w>
" Set the vertical split character to a space (there is a single space after '\ ')
:set fillchars+=vert:\
" Open terminal with our setup file loaded
nmap <Leader>T :vsplit \| execute "terminal" \| startinsert <CR>
tmap <Leader>T <C-\><C-n>:vsplit \| execute "terminal" \| startinsert <CR>
nmap <Leader>t :split \| execute "terminal" \| startinsert <CR>
tmap <Leader>t <C-\><C-n>:split \| execute "terminal" \| startinsert <CR>
" Force quit a window
tnoremap <Leader>q <C-\><C-n>:bd!<CR>
noremap <Leader>q <C-w>:bd!<CR>
" Save session state (buffers, splits, file locations, etc) - Obsession
noremap <F2> :Obsess! tmp/Session.vim <cr> " Quick write session with F2
" remap git blame command
nnoremap <Leader>bl :<C-u>call gitblame#echo()<CR>
let g:NERDTreeGitStatusIndicatorMapCustom = {
\ 'Modified' :'m',
\ 'Staged' :'+',
\ 'Untracked' :'u',
\ 'Renamed' :'r',
\ 'Unmerged' :'',
\ 'Deleted' :'x',
\ 'Dirty' :'',
\ 'Ignored' :'i',
\ 'Clean' :'',
\ 'Unknown' :'',
\ }
" Nerd tree
nnoremap <leader>n :NERDTreeFocus<CR>
nnoremap <C-n> :NERDTree<CR>
nnoremap <C-t> :NERDTreeToggle<CR>
nnoremap <C-f> :NERDTreeFind<CR>
" If another buffer tries to replace NERDTree, put it in the other window, and bring back NERDTree.
autocmd BufEnter * if bufname('#') =~ 'NERD_tree_\d\+' && bufname('%') !~ 'NERD_tree_\d\+' && winnr('$') > 1 |
\ let buf=bufnr() | buffer# | execute "normal! \<C-W>w" | execute 'buffer'.buf | endif
let g:WebDevIconsDisableDefaultFolderSymbolColorFromNERDTreeDir = 1
let g:WebDevIconsDisableDefaultFileSymbolColorFromNERDTreeFile = 1
let g:NERDTreeSyntaxDisableDefaultExtensions = 1
let g:NERDTreeSyntaxDisableDefaultExactMatches = 1
let g:NERDTreeSyntaxDisableDefaultPatternMatches = 1
let NERDTreeDirArrowExpandable="▶"
let NERDTreeDirArrowCollapsible="▽"
let g:NERDTreeGitStatusUseNerdFonts = 1
augroup nerdtreeconcealbrackets
autocmd!
autocmd FileType nerdtree syntax match hideBracketsInNerdTree "\]" contained conceal containedin=ALL cchar=
autocmd FileType nerdtree syntax match hideBracketsInNerdTree "\[" contained conceal containedin=ALL
autocmd FileType nerdtree setlocal conceallevel=2
autocmd FileType nerdtree setlocal concealcursor=nvic
augroup END
" Tab key to select a value from autocomplete list
inoremap <silent><expr> <TAB>
\ coc#pum#visible() ? coc#pum#next(1) :
\ CheckBackspace() ? "\<Tab>" :
\ coc#refresh()
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"
" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice.
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
function! CheckBackspace() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
" Use <c-space> to trigger completion.
if has('nvim')
inoremap <silent><expr> <c-space> coc#refresh()
else
inoremap <silent><expr> <c-@> coc#refresh()
endif
" GoTo code navigation.
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
" Use K to show documentation in preview window.
nnoremap <silent> K :call ShowDocumentation()<CR>
function! ShowDocumentation()
if CocAction('hasProvider', 'hover')
call CocActionAsync('doHover')
else
call feedkeys('K', 'in')
endif
endfunction
" Highlight symbol under cursor on CursorHold
autocmd CursorHold * silent call CocActionAsync('highlight')
let g:javascript_conceal_function = "ƒ"
let g:javascript_conceal_arrow_function = "⇒"
let g:typescript_conceal_function = "ƒ"
let g:typescript_conceal_arrow_function = "⇒"
autocmd FileType scss setl iskeyword+=@-@
let g:rustfmt_autosave = 1
function! BuildComposer(info)
if a:info.status != 'unchanged' || a:info.force
if has('nvim')
!cargo build --release --locked
else
!cargo build --release --locked --no-default-features --features json-rpc
endif
endif
endfunction