Add tree-quickjump
This commit is contained in:
parent
662bcbc908
commit
e9546cb0e8
|
@ -19,9 +19,11 @@ map -docstring "disable highlighting" global tree '&' ":tree-always-hig
|
||||||
declare-user-mode tree-children
|
declare-user-mode tree-children
|
||||||
declare-user-mode tree-next
|
declare-user-mode tree-next
|
||||||
declare-user-mode tree-prev
|
declare-user-mode tree-prev
|
||||||
|
declare-user-mode tree-quickjump
|
||||||
|
|
||||||
map global normal 'f' ":enter-user-mode tree-next<ret>"
|
map global normal 'f' ":enter-user-mode tree-quickjump<ret>"
|
||||||
map global normal 'F' ":enter-user-mode tree-children<ret>"
|
map global normal 'F' ":enter-user-mode tree-next<ret>"
|
||||||
|
map global normal '<a-f>' ":enter-user-mode tree-children<ret>"
|
||||||
|
|
||||||
evaluate-commands %sh{
|
evaluate-commands %sh{
|
||||||
echo "i,identifier
|
echo "i,identifier
|
||||||
|
@ -37,6 +39,7 @@ while IFS=, read -r cmd group ; do
|
||||||
echo "map -docstring '$group child' global tree-children '$cmd' ':tree-select-children $group<ret>'"
|
echo "map -docstring '$group child' global tree-children '$cmd' ':tree-select-children $group<ret>'"
|
||||||
echo "map -docstring 'next $group' global tree-next '$cmd' ':tree-select-next-node $group<ret>'"
|
echo "map -docstring 'next $group' global tree-next '$cmd' ':tree-select-next-node $group<ret>'"
|
||||||
echo "map -docstring 'previous $group' global tree-prev '$cmd' ':tree-select-previous-node $group<ret>'"
|
echo "map -docstring 'previous $group' global tree-prev '$cmd' ':tree-select-previous-node $group<ret>'"
|
||||||
|
echo "map -docstring 'quickjump to $group' global tree-quickjump '$cmd' ':tree-quickjump $group<ret>'"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
39
rc/tree.kak
39
rc/tree.kak
|
@ -16,6 +16,15 @@ declare-option str tree_highlight_style "black,blue"
|
||||||
declare-option -hidden range-specs tree_highlight
|
declare-option -hidden range-specs tree_highlight
|
||||||
add-highlighter global/tree_highlight ranges tree_highlight
|
add-highlighter global/tree_highlight ranges tree_highlight
|
||||||
|
|
||||||
|
declare-option str tree_quickjump_highlight_style "black,green"
|
||||||
|
declare-option -hidden range-specs tree_quickjump_replace
|
||||||
|
add-highlighter global/tree_quickjump_replace replace-ranges tree_quickjump_replace
|
||||||
|
|
||||||
|
declare-option -hidden range-specs tree_quickjump_highlight
|
||||||
|
add-highlighter global/tree_quickjump_highlight ranges tree_quickjump_highlight
|
||||||
|
|
||||||
|
declare-option -hidden range-specs tree_quickjump
|
||||||
|
|
||||||
define-command -hidden tree-command -params 1..2 -docstring %{
|
define-command -hidden tree-command -params 1..2 -docstring %{
|
||||||
tree-command <OP_TYPE> [<OP_PARAMS>]
|
tree-command <OP_TYPE> [<OP_PARAMS>]
|
||||||
Send request to kak-tree and evaluate response.
|
Send request to kak-tree and evaluate response.
|
||||||
|
@ -89,6 +98,36 @@ define-command tree-select-first-child -params ..1 -docstring %{
|
||||||
execute-keys ,
|
execute-keys ,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define-command tree-quickjump -params 1 -docstring %{
|
||||||
|
tree-quickjump [<KIND>]
|
||||||
|
Opens a menu to jump to a node of the specified kind
|
||||||
|
} %{
|
||||||
|
tree-command-with-optional-kind QuickJump %arg{1}
|
||||||
|
|
||||||
|
# We have now set the tree_quickjump variable to contain each location to jump to
|
||||||
|
prompt -menu \
|
||||||
|
-shell-script-candidates 'IFS=" "; for entry in $kak_opt_tree_quickjump ; do echo "${entry#*|}" ; done' "Jump to " \
|
||||||
|
-on-abort %{
|
||||||
|
set-option buffer tree_quickjump "%val{timestamp}"
|
||||||
|
set-option buffer tree_quickjump_highlight "%val{timestamp}"
|
||||||
|
set-option buffer tree_quickjump_replace "%val{timestamp}"
|
||||||
|
} \
|
||||||
|
%{evaluate-commands %sh{
|
||||||
|
# loop through tree_quickjump to find the corresponding selection
|
||||||
|
IFS=" "
|
||||||
|
for entry in $kak_opt_tree_quickjump ; do
|
||||||
|
echo "echo -debug \"testing $entry ($kak_text)\""
|
||||||
|
[ "$entry" = "${entry%|$kak_text}" ] && continue
|
||||||
|
echo "echo -debug \"yes\""
|
||||||
|
echo "select ${entry%|$kak_text}"
|
||||||
|
done
|
||||||
|
echo 'set-option buffer tree_quickjump "%val{timestamp}"'
|
||||||
|
echo 'set-option buffer tree_quickjump_highlight "%val{timestamp}"'
|
||||||
|
echo 'set-option buffer tree_quickjump_replace "%val{timestamp}"'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
define-command tree-node-highlight -docstring %{
|
define-command tree-node-highlight -docstring %{
|
||||||
tree-node-highlight
|
tree-node-highlight
|
||||||
Highlight the current node using the tree_highlight_style face
|
Highlight the current node using the tree_highlight_style face
|
||||||
|
|
|
@ -10,13 +10,14 @@ pub fn select_ranges(buffer: &[String], ranges: &[Range]) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn highlight_ranges(buffer: &[String], ranges: &[Range]) -> String {
|
pub fn highlight_ranges(buffer: &[String], ranges: &[Range]) -> String {
|
||||||
format!("set-option buffer tree_highlight %val{{timestamp}} {}", ranges_to_range_desc(&buffer, &ranges, "%opt{tree_highlight_style}".to_string()))
|
format!("set-option buffer tree_highlight %val{{timestamp}} {}", ranges_to_range_desc(&buffer, &ranges, |_i| "%opt{tree_highlight_style}".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ranges_to_range_desc(buffer: &[String], ranges: &[Range], string: String) -> String {
|
pub fn ranges_to_range_desc<F: Fn(usize) -> String>(buffer: &[String], ranges: &[Range], decorate: F) -> String {
|
||||||
ranges
|
ranges
|
||||||
.iter()
|
.iter()
|
||||||
.map(|range| {
|
.enumerate()
|
||||||
|
.map(|(i, range)| {
|
||||||
let mut end_row = range.end_point.row;
|
let mut end_row = range.end_point.row;
|
||||||
let mut end_column = range.end_point.column;
|
let mut end_column = range.end_point.column;
|
||||||
if end_column > 0 {
|
if end_column > 0 {
|
||||||
|
@ -29,7 +30,7 @@ pub fn ranges_to_range_desc(buffer: &[String], ranges: &[Range], string: String)
|
||||||
"\"{},{}|{}\"",
|
"\"{},{}|{}\"",
|
||||||
point_to_kak_coords(buffer, range.start_point),
|
point_to_kak_coords(buffer, range.start_point),
|
||||||
point_to_kak_coords(buffer, Point::new(end_row, end_column)),
|
point_to_kak_coords(buffer, Point::new(end_row, end_column)),
|
||||||
string,
|
decorate(i),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.join(" ")
|
.join(" ")
|
||||||
|
@ -113,3 +114,4 @@ fn kak_coords_to_byte_and_point(buffer: &[String], coords: &str) -> (usize, Poin
|
||||||
.unwrap();
|
.unwrap();
|
||||||
(byte, Point::new(row, column))
|
(byte, Point::new(row, column))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
109
src/main.rs
109
src/main.rs
|
@ -3,7 +3,7 @@ use clap::{crate_version, App, Arg};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use toml;
|
use toml;
|
||||||
use tree_sitter::{Node, Parser, Range};
|
use tree_sitter::{Node, Parser, Range, Point};
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod ffi;
|
mod ffi;
|
||||||
|
@ -28,6 +28,7 @@ enum Op {
|
||||||
SelectParentNode { kind: Option<String> },
|
SelectParentNode { kind: Option<String> },
|
||||||
SelectPreviousNode { kind: Option<String> },
|
SelectPreviousNode { kind: Option<String> },
|
||||||
SelectNode,
|
SelectNode,
|
||||||
|
QuickJump { kind: Option<String> },
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -132,7 +133,7 @@ fn handle_request(config: &Config, request: &Request) -> String {
|
||||||
loop {
|
loop {
|
||||||
let parent = cursor.parent();
|
let parent = cursor.parent();
|
||||||
loop {
|
loop {
|
||||||
if filetype_config.is_node_visible(cursor) && node_of_kinds(cursor, &kinds) {
|
if filetype_config.is_node_visible(cursor) && node_of_kinds(cursor, kinds.as_deref()) {
|
||||||
if cursor != node {
|
if cursor != node {
|
||||||
new_ranges.push(cursor.range());
|
new_ranges.push(cursor.range());
|
||||||
continue 'outer_next;
|
continue 'outer_next;
|
||||||
|
@ -197,6 +198,60 @@ fn handle_request(config: &Config, request: &Request) -> String {
|
||||||
}
|
}
|
||||||
kakoune::highlight_ranges(&buffer, &new_ranges)
|
kakoune::highlight_ranges(&buffer, &new_ranges)
|
||||||
}
|
}
|
||||||
|
Op::QuickJump { kind } => {
|
||||||
|
const LETTERS: &[char] = &[
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||||
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'å', 'ä', 'ö',
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Å', 'Ä', 'Ö',
|
||||||
|
];
|
||||||
|
|
||||||
|
let kind = kind.clone().unwrap();
|
||||||
|
let main_range = &ranges[0];
|
||||||
|
let main_node = tree::shrink_to_range(tree.root_node(), main_range);
|
||||||
|
let kinds = filetype_config.resolve_alias(&kind);
|
||||||
|
|
||||||
|
let mut nodes = next_n_nodes_of_kind(main_node, &kinds, LETTERS.len() / 2, Direction::Forward);
|
||||||
|
nodes.extend(next_n_nodes_of_kind(main_node, &kinds, LETTERS.len() - nodes.len(), Direction::Backward));
|
||||||
|
|
||||||
|
for node in &nodes {
|
||||||
|
new_ranges.push(node.range());
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't want any ranges that overlap the first char
|
||||||
|
let mut longest_at_point: std::collections::HashMap<Point, usize> = Default::default();
|
||||||
|
for range in &new_ranges {
|
||||||
|
let range_len = range.end_byte - range.start_byte;
|
||||||
|
|
||||||
|
longest_at_point.insert(
|
||||||
|
range.start_point,
|
||||||
|
longest_at_point.get(&range.start_point).copied().unwrap_or(0).max(range_len)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_ranges.retain(|range| {
|
||||||
|
let range_len = range.end_byte - range.start_byte;
|
||||||
|
range_len >= longest_at_point.get(&range.start_point).copied().unwrap_or(0)
|
||||||
|
});
|
||||||
|
|
||||||
|
eprintln!("ranges = {:?}", new_ranges);
|
||||||
|
|
||||||
|
let new_ranges_first_char: Vec<Range> = new_ranges
|
||||||
|
.iter()
|
||||||
|
.map(|range| Range {
|
||||||
|
start_byte: range.start_byte, end_byte: range.start_byte,
|
||||||
|
start_point: range.start_point,
|
||||||
|
end_point: Point { row: range.start_point.row, column: range.start_point.column + 1 },
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let replace_ranges = format!("set-option buffer tree_quickjump_replace %val{{timestamp}} {}", kakoune::ranges_to_range_desc(&buffer, &new_ranges_first_char, |i| LETTERS[i].to_string()));
|
||||||
|
|
||||||
|
let highlight_ranges = format!("set-option buffer tree_quickjump_highlight %val{{timestamp}} {}", kakoune::ranges_to_range_desc(&buffer, &new_ranges_first_char, |_i| "%opt{tree_quickjump_highlight_style}".to_string()));
|
||||||
|
|
||||||
|
let set_option = format!("set-option buffer tree_quickjump %val{{timestamp}} {}", kakoune::ranges_to_range_desc(&buffer, &new_ranges, |i| LETTERS[i].to_string()));
|
||||||
|
|
||||||
|
format!("{replace_ranges} ; {highlight_ranges} ; {set_option}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +297,55 @@ fn find_parent_of_interest<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_of_kinds(node: Node, kinds: &Option<Vec<String>>) -> bool {
|
enum Direction {
|
||||||
|
Forward, Backward,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_n_nodes_of_kind<'a>(node: Node<'a>, kinds: &[String], n: usize, dir: Direction) -> Vec<Node<'a>> {
|
||||||
|
let mut current = node;
|
||||||
|
|
||||||
|
let mut visited = Vec::new();
|
||||||
|
|
||||||
|
'outer: while visited.len() < n {
|
||||||
|
eprintln!("At node kind = {}, {current:?}", node.kind());
|
||||||
|
if kinds.iter().any(|kind| kind == current.kind()) {
|
||||||
|
visited.push(current);
|
||||||
|
}
|
||||||
|
let first_child = match dir {
|
||||||
|
Direction::Forward => current.child(0),
|
||||||
|
Direction::Backward => current.child(current.child_count() - 1),
|
||||||
|
};
|
||||||
|
if let Some(first_child) = first_child {
|
||||||
|
current = first_child;
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
match dir {
|
||||||
|
Direction::Forward => {
|
||||||
|
if let Some(sibling) = current.next_sibling() {
|
||||||
|
current = sibling;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Backward => {
|
||||||
|
if let Some(sibling) = current.prev_sibling() {
|
||||||
|
current = sibling;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(parent) = current.parent() {
|
||||||
|
current = parent;
|
||||||
|
} else {
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visited
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_of_kinds(node: Node, kinds: Option<&[String]>) -> bool {
|
||||||
kinds
|
kinds
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|kinds| Some(kinds.iter().any(|x| x == node.kind())))
|
.and_then(|kinds| Some(kinds.iter().any(|x| x == node.kind())))
|
||||||
|
|
|
@ -37,3 +37,4 @@ fn highest_node_of_same_range<'a>(current_node: Node<'a>) -> Node<'a> {
|
||||||
}
|
}
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user