Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add preview support for help_tags #630

Merged
merged 7 commits into from
Feb 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Add `g:ClapProviderHistoryCustomFilter` for customizing the source of `history` provider. #615
- Add a bonus for the match in the filename when the source item is a path, but you can only have this when you are using Python dynamic module or the Rust backend. #614.
- Add a bonus for the files you opened since you enter vim. #622
- Add async preview support for `help_tags` provider, the Rust binary is required. #630

### Fixed

Expand Down
3 changes: 3 additions & 0 deletions autoload/clap/client.vim
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ function! clap#client#notify_on_init(method, ...) abort
\ 'provider_id': g:clap.provider.id,
\ 'source_fpath': expand('#'.g:clap.start.bufnr.':p'),
\ }
if g:clap.provider.id ==# 'help_tags'
let params['runtimepath'] = &runtimepath
endif
if a:0 > 0
call extend(params, a:1)
endif
Expand Down
11 changes: 10 additions & 1 deletion autoload/clap/impl/on_move.vim
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ if clap#maple#is_available()
catch
return
endtry
if has_key(a:result, 'fname')
if has_key(a:result, 'syntax')
call g:clap.preview.set_syntax(a:result.syntax)
elseif has_key(a:result, 'fname')
call g:clap.preview.set_syntax(clap#ext#into_filetype(a:result.fname))
endif
call clap#preview#highlight_header()
Expand All @@ -45,10 +47,17 @@ if clap#maple#is_available()
endif
call s:sync_run_with_delay()
endfunction

function! clap#impl#on_move#async() abort
return clap#client#call_on_move('on_move', function('s:handle_on_move_result'))
endfunction
else
function! s:dispatch_on_move_impl() abort
call s:sync_run_with_delay()
endfunction

function! clap#impl#on_move#async() abort
endfunction
endif

function! clap#impl#on_move#invoke() abort
Expand Down
4 changes: 3 additions & 1 deletion autoload/clap/provider/help_tags.vim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
let s:save_cpo = &cpoptions
set cpoptions&vim

let s:help_tags = {}

function! s:get_doc_tags() abort
return ['/doc/tags'] + map(filter(split(&helplang, ','), 'v:val !=? "en"'), '"/doc/tags-".v:val')
endfunction
Expand All @@ -27,6 +29,7 @@ if clap#maple#is_available() && clap#filter#sync#python#has_dynamic_module()
endif
endfunction

let s:help_tags.on_move_async = function('clap#impl#on_move#async')
else

let s:help_tags_memory_cache = []
Expand Down Expand Up @@ -78,7 +81,6 @@ else
endfunction
endif

let s:help_tags = {}
let s:help_tags.sink = function('s:help_tags_sink')
let s:help_tags.source = function('s:help_tags_source')

Expand Down
3 changes: 2 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
fn main() {
built::write_built_file().expect("Failed to acquire build-time information");
built::write_built_file()
.unwrap_or_else(|e| panic!("Failed to acquire build-time information: {:?}", e));
}
10 changes: 5 additions & 5 deletions crates/maple_cli/src/cmd/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl Cache {
.file_name()
.and_then(std::ffi::OsStr::to_str)
.map(Into::into)
.expect("Couldn't get file name")
.unwrap_or_else(|| panic!("Couldn't get file name"))
})
})
.collect::<Result<Vec<String>, std::io::Error>>()?;
Expand All @@ -73,11 +73,11 @@ pub struct CacheEntry;
impl CacheEntry {
/// Construct the cache entry given command arguments and its working directory, the `total`
/// info is cached in the file name.
pub fn new(cmd_args: &[&str], cmd_dir: Option<PathBuf>, total: usize) -> Result<PathBuf> {
pub fn try_new(cmd_args: &[&str], cmd_dir: Option<PathBuf>, total: usize) -> Result<PathBuf> {
let mut dir = clap_cache_dir();
dir.push(cmd_args.join("_"));
if let Some(mut cmd_dir) = cmd_dir {
dir.push(format!("{}", calculate_hash(&mut cmd_dir)));
if let Some(cmd_dir) = cmd_dir {
dir.push(format!("{}", calculate_hash(&cmd_dir)));
} else {
dir.push("no_cmd_dir");
}
Expand Down Expand Up @@ -117,7 +117,7 @@ impl CacheEntry {
total: usize,
contents: T,
) -> Result<PathBuf> {
let entry = Self::new(cmd_args, cmd_dir, total)?;
let entry = Self::try_new(cmd_args, cmd_dir, total)?;
Self::write(&entry, contents)?;
Ok(entry)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/maple_cli/src/light_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl CommandEnv {
if let Some(ref output) = self.output {
Ok(output.into())
} else {
CacheEntry::new(args, self.dir.clone(), self.total)
CacheEntry::try_new(args, self.dir.clone(), self.total)
}
}

Expand Down
8 changes: 5 additions & 3 deletions crates/printer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ pub fn truncate_long_matched_lines<T>(
let line = item.display_text.unwrap_or(item.raw);
lnum += 1;
if !indices.is_empty() {
let last_idx = indices.last().expect("indices are non-empty; qed");
let last_idx = indices
.last()
.unwrap_or_else(|| panic!("indices are non-empty; qed"));
if *last_idx > winwidth {
let mut start = *last_idx - winwidth;
if start >= indices[0] || (indices.len() > 1 && *last_idx - start > winwidth) {
Expand Down Expand Up @@ -98,10 +100,10 @@ pub fn truncate_long_matched_lines<T>(
truncated_map.insert(lnum, line);
(truncated, score, truncated_indices)
} else {
(line.into(), score, indices)
(line, score, indices)
}
} else {
(line.into(), score, indices)
(line, score, indices)
}
})
.collect::<Vec<_>>();
Expand Down
2 changes: 1 addition & 1 deletion crates/stdio_server/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub fn initialize_global(msg: Message) {
let preview_size = msg
.params
.get("clap_preview_size")
.expect("Missing clap_preview_size on initialize_global_env");
.unwrap_or_else(|| panic!("Missing clap_preview_size on initialize_global_env"));

let global_env = GlobalEnv::new(is_nvim, enable_icon, preview_size.clone());

Expand Down
2 changes: 1 addition & 1 deletion crates/stdio_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,6 @@ where
.spawn(move || {
loop_read_rpc_message(reader, &tx);
})
.expect("Failed to spawn rpc reader thread");
.unwrap_or_else(|_| panic!("Failed to spawn rpc reader thread"));
loop_handle_rpc_message(&rx);
}
9 changes: 8 additions & 1 deletion crates/stdio_server/src/session/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct SessionContext {
pub source_cmd: Option<String>,
pub winwidth: Option<u64>,
pub provider_id: ProviderId,
pub runtimepath: Option<String>,
pub start_buffer_path: String,
pub is_running: Arc<Mutex<AtomicBool>>,
pub source_list: Arc<Mutex<Option<Vec<String>>>>,
Expand All @@ -29,6 +30,11 @@ impl From<Message> for SessionContext {

let cwd = msg.get_cwd();

let runtimepath = msg
.params
.get("runtimepath")
.and_then(|x| x.as_str().map(Into::into));

let source_cmd = msg
.params
.get("source_cmd")
Expand All @@ -40,13 +46,14 @@ impl From<Message> for SessionContext {
msg.params
.get("source_fpath")
.and_then(|x| x.as_str())
.expect("Missing source_fpath"),
.unwrap_or_else(|| panic!("Missing source_fpath")),
);

Self {
provider_id,
cwd,
source_cmd,
runtimepath,
winwidth,
start_buffer_path,
is_running: Arc::new(Mutex::new(true.into())),
Expand Down
5 changes: 3 additions & 2 deletions crates/stdio_server/src/session/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ impl HandleMessage for MessageHandler {
match msg {
RpcMessage::OnMove(msg) => {
let msg_id = msg.id;
if let Err(e) = on_move::OnMoveHandler::try_new(msg, context).map(|x| x.handle()) {
write_response(json!({ "error": format!("{}",e), "id": msg_id }));
if let Err(e) = on_move::OnMoveHandler::try_new(&msg, context).map(|x| x.handle()) {
log::debug!("Handle RpcMessage::OnMove {:?}, error: {:?}", msg, e);
write_response(json!({"error": format!("{}",e), "id": msg_id }));
}
}
RpcMessage::OnTyped(msg) => on_typed::handle_on_typed(msg, context),
Expand Down
114 changes: 108 additions & 6 deletions crates/stdio_server/src/session/handler/on_move.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,51 @@ pub fn as_absolute_path<P: AsRef<Path>>(path: P) -> Result<String> {
.map_err(|e| anyhow!("{:?}, path:{}", e, path.as_ref().display()))
}

#[derive(Debug, Clone)]
struct PreviewTag {
subject: String,
doc_filename: String,
runtimepath: String,
}

fn find_tag_line(p: &PathBuf, subject: &str) -> Option<usize> {
if let Ok(doc_lines) = utility::read_lines(p) {
for (idx, doc_line) in doc_lines.enumerate() {
if let Ok(d_line) = doc_line {
if d_line.trim().contains(&format!("*{}*", subject)) {
return Some(idx);
}
}
}
}
None
}

impl PreviewTag {
pub fn new(subject: String, doc_filename: String, runtimepath: String) -> Self {
Self {
subject,
doc_filename,
runtimepath,
}
}

pub fn get_help_lines(&self, size: usize) -> Option<(String, Vec<String>)> {
for r in self.runtimepath.split(',') {
let p = Path::new(r).join("doc").join(&self.doc_filename);
if p.exists() {
if let Some(line_number) = find_tag_line(&p, &self.subject) {
if let Ok(lines_iter) = utility::read_lines_from(&p, line_number, size) {
return Some((format!("{}", p.display()), lines_iter.collect()));
}
}
}
}

None
}
}

/// Preview environment on Vim CursorMoved event.
#[derive(Debug, Clone)]
#[allow(dead_code)]
Expand All @@ -27,10 +72,27 @@ pub enum OnMove {
Files(PathBuf),
Filer(PathBuf),
History(PathBuf),
Grep { path: PathBuf, lnum: usize },
BLines { path: PathBuf, lnum: usize },
ProjTags { path: PathBuf, lnum: usize },
BufferTags { path: PathBuf, lnum: usize },
Grep {
path: PathBuf,
lnum: usize,
},
BLines {
path: PathBuf,
lnum: usize,
},
ProjTags {
path: PathBuf,
lnum: usize,
},
BufferTags {
path: PathBuf,
lnum: usize,
},
HelpTags {
subject: String,
doc_filename: String,
runtimepath: String,
},
}

/// Build the absolute path using cwd and relative path.
Expand Down Expand Up @@ -82,6 +144,23 @@ impl OnMove {
let path = context.start_buffer_path.clone().into();
Self::BufferTags { path, lnum }
}
"help_tags" => {
let runtimepath = context
.runtimepath
.clone()
.context("no runtimepath in the context")?;
let items = curline.split('\t').collect::<Vec<_>>();
if items.len() < 2 {
return Err(anyhow!(
"Can not extract subject and doc_filename from the line"
));
}
Self::HelpTags {
subject: items[0].trim().to_string(),
doc_filename: items[1].trim().to_string(),
runtimepath,
}
}
"commits" | "bcommits" => {
let rev = parse_rev(&curline).context("can not extract rev")?;
Self::Commit(rev.into())
Expand All @@ -107,7 +186,7 @@ pub struct OnMoveHandler<'a> {
}

impl<'a> OnMoveHandler<'a> {
pub fn try_new(msg: Message, context: &'a SessionContext) -> anyhow::Result<Self> {
pub fn try_new(msg: &Message, context: &'a SessionContext) -> anyhow::Result<Self> {
let msg_id = msg.id;
let provider_id = context.provider_id.clone();
let curline = msg.get_curline(&provider_id)?;
Expand Down Expand Up @@ -140,6 +219,11 @@ impl<'a> OnMoveHandler<'a> {
debug!("path:{}, lnum:{}", path.display(), lnum);
self.preview_file_at(&path, *lnum);
}
HelpTags {
subject,
doc_filename,
runtimepath,
} => self.preview_help_subject(subject, doc_filename, runtimepath),
Filer(path) if path.is_dir() => {
self.preview_directory(&path)?;
}
Expand All @@ -155,7 +239,7 @@ impl<'a> OnMoveHandler<'a> {
}

fn send_response(&self, result: serde_json::value::Value) {
let provider_id: crate::types::ProviderId = self.provider_id.clone().into();
let provider_id: crate::types::ProviderId = self.provider_id.clone();
write_response(json!({
"id": self.msg_id,
"provider_id": provider_id,
Expand All @@ -177,6 +261,24 @@ impl<'a> OnMoveHandler<'a> {
Ok(())
}

fn preview_help_subject(&self, subject: &str, doc_filename: &str, runtimepath: &str) {
let preview_tag = PreviewTag::new(subject.into(), doc_filename.into(), runtimepath.into());
if let Some((fname, lines)) = preview_tag.get_help_lines(self.size * 2) {
let lines = std::iter::once(fname.clone())
.chain(lines.into_iter())
.collect::<Vec<_>>();
self.send_response(json!({
"event": "on_move",
"syntax": "help",
"lines": lines,
"hi_lnum": 1,
"fname": fname
}));
} else {
debug!("Can not find the preview help lines for {:?}", preview_tag);
}
}

fn preview_file_at<P: AsRef<Path>>(&self, path: P, lnum: usize) {
match utility::read_preview_lines(path.as_ref(), lnum, self.size) {
Ok((lines_iter, hi_lnum)) => {
Expand Down
6 changes: 3 additions & 3 deletions crates/stdio_server/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,22 @@ impl Message {
.get(key)
.and_then(|x| x.as_str())
.map(Into::into)
.expect(&format!("Missing {} in msg.params", key))
.unwrap_or_else(|| panic!("Missing {} in msg.params", key))
}

fn _get_string(&self, key: &str) -> anyhow::Result<String> {
self.params
.get(key)
.and_then(|x| x.as_str())
.map(Into::into)
.ok_or(anyhow::anyhow!("Missing {} in msg.params", key))
.ok_or_else(|| anyhow::anyhow!("Missing {} in msg.params", key))
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ProviderId(String);

const NO_ICON_PROVIDERS: [&str; 3] = ["blines", "commits", "bcommits"];
const NO_ICON_PROVIDERS: [&str; 4] = ["blines", "commits", "bcommits", "help_tags"];

impl ProviderId {
pub fn as_str(&self) -> &str {
Expand Down
Loading