aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_cli/Cargo.toml1
-rw-r--r--crates/ra_cli/src/main.rs33
-rw-r--r--crates/ra_syntax/src/algo/mod.rs6
-rw-r--r--editors/emacs/ra.el86
4 files changed, 123 insertions, 3 deletions
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index 17011e063..5e7bf3ed4 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -7,6 +7,7 @@ publish = false
7[dependencies] 7[dependencies]
8clap = "2.32.0" 8clap = "2.32.0"
9failure = "0.1.1" 9failure = "0.1.1"
10join_to_string = "0.1.1"
10ra_syntax = { path = "../ra_syntax" } 11ra_syntax = { path = "../ra_syntax" }
11ra_editor = { path = "../ra_editor" } 12ra_editor = { path = "../ra_editor" }
12tools = { path = "../tools" } 13tools = { path = "../tools" }
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 96e5b718c..11605cfd8 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -1,6 +1,7 @@
1extern crate clap; 1extern crate clap;
2#[macro_use] 2#[macro_use]
3extern crate failure; 3extern crate failure;
4extern crate join_to_string;
4extern crate ra_syntax; 5extern crate ra_syntax;
5extern crate ra_editor; 6extern crate ra_editor;
6extern crate tools; 7extern crate tools;
@@ -10,9 +11,10 @@ use std::{
10 time::Instant 11 time::Instant
11}; 12};
12use clap::{App, Arg, SubCommand}; 13use clap::{App, Arg, SubCommand};
14use join_to_string::join;
13use tools::collect_tests; 15use tools::collect_tests;
14use ra_syntax::File; 16use ra_syntax::{TextRange, File};
15use ra_editor::{syntax_tree, file_structure}; 17use ra_editor::{syntax_tree, file_structure, extend_selection};
16 18
17type Result<T> = ::std::result::Result<T, failure::Error>; 19type Result<T> = ::std::result::Result<T, failure::Error>;
18 20
@@ -39,6 +41,10 @@ fn main() -> Result<()> {
39 .arg(Arg::with_name("no-dump").long("--no-dump")) 41 .arg(Arg::with_name("no-dump").long("--no-dump"))
40 ) 42 )
41 .subcommand(SubCommand::with_name("symbols")) 43 .subcommand(SubCommand::with_name("symbols"))
44 .subcommand(SubCommand::with_name("extend-selection")
45 .arg(Arg::with_name("start"))
46 .arg(Arg::with_name("end"))
47 )
42 .get_matches(); 48 .get_matches();
43 match matches.subcommand() { 49 match matches.subcommand() {
44 ("parse", Some(matches)) => { 50 ("parse", Some(matches)) => {
@@ -65,6 +71,13 @@ fn main() -> Result<()> {
65 let (test, tree) = render_test(file, line)?; 71 let (test, tree) = render_test(file, line)?;
66 println!("{}\n{}", test, tree); 72 println!("{}\n{}", test, tree);
67 } 73 }
74 ("extend-selection", Some(matches)) => {
75 let start: u32 = matches.value_of("start").unwrap().parse()?;
76 let end: u32 = matches.value_of("end").unwrap().parse()?;
77 let file = file()?;
78 let sels = selections(&file, start, end);
79 println!("{}", sels)
80 }
68 _ => unreachable!(), 81 _ => unreachable!(),
69 } 82 }
70 Ok(()) 83 Ok(())
@@ -95,3 +108,19 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
95 let tree = syntax_tree(&file); 108 let tree = syntax_tree(&file);
96 Ok((test.text, tree)) 109 Ok((test.text, tree))
97} 110}
111
112fn selections(file: &File, start: u32, end: u32) -> String {
113 let mut ranges = Vec::new();
114 let mut cur = Some(TextRange::from_to((start - 1).into(), (end - 1).into()));
115 while let Some(r) = cur {
116 ranges.push(r);
117 cur = extend_selection(&file, r);
118 }
119 let ranges = ranges.iter()
120 .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end())))
121 .map(|(s, e)| format!("({} {})", s, e));
122 join(ranges)
123 .separator(" ")
124 .surround_with("(", ")")
125 .to_string()
126}
diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs
index 7287f5bb2..8de44c586 100644
--- a/crates/ra_syntax/src/algo/mod.rs
+++ b/crates/ra_syntax/src/algo/mod.rs
@@ -78,7 +78,11 @@ impl<'f> Iterator for LeafAtOffset<'f> {
78} 78}
79 79
80pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef { 80pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef {
81 assert!(is_subrange(root.range(), range)); 81 assert!(
82 is_subrange(root.range(), range),
83 "node range: {:?}, target range: {:?}",
84 root.range(), range,
85 );
82 let (left, right) = match ( 86 let (left, right) = match (
83 find_leaf_at_offset(root, range.start()).right_biased(), 87 find_leaf_at_offset(root, range.start()).right_biased(),
84 find_leaf_at_offset(root, range.end()).left_biased() 88 find_leaf_at_offset(root, range.end()).left_biased()
diff --git a/editors/emacs/ra.el b/editors/emacs/ra.el
new file mode 100644
index 000000000..6ff2ae742
--- /dev/null
+++ b/editors/emacs/ra.el
@@ -0,0 +1,86 @@
1;;; ra.el --- Rust analyzer emacs bindings -*- lexical-binding: t; -*-
2;;; Commentary:
3;;; Small utilities for interacting with Rust analyzer.
4;;; Run
5;;; cargo install --git https://github.com/matklad/rust-analyzer/ --bin ra_cli
6;;; to install the binary, copy-paste the bellow code to your `.init.el` and use
7;;; `ra-extend-selection` and `ra-shrink-selection` functions
8;;; Code:
9
10
11(defvar ra--selections-cache '(0 0 ()))
12(defun ra--cache-tick ()
13 "Get buffer modification count for cache."
14 (nth 0 ra--selections-cache))
15(defun ra--cache-sel ()
16 "Get current selection for cache."
17 (nth 1 ra--selections-cache))
18(defun ra--cache-nth-sel (n)
19 "Get Nth selection."
20 (nth n (nth 2 ra--selections-cache)))
21(defun ra--cache-set-nth-sel (n)
22 "Get Nth selection."
23 (setf (nth 1 ra--selections-cache) n)
24 (nth n (nth 2 ra--selections-cache)))
25
26
27(defun ra-extend-selection ()
28 "Extend START END region to contain the encompassing syntactic construct."
29 (interactive)
30 (let* ((p (point))
31 (m (or (and mark-active (mark)) p))
32 (start (min p m))
33 (end (max p m)))
34 (ra--extend-selection start end)))
35
36
37(defun ra-shrink-selection (start end)
38 "Shrink START END region to contain previous selection."
39 (interactive "r")
40 (ra--freshen-cache start end)
41 (let ((sel-id (ra--cache-sel)))
42 (if (not (= 0 sel-id))
43 (let* ((r (ra--cache-set-nth-sel (- sel-id 1))))
44 (push-mark (nth 0 r) t t)
45 (goto-char (nth 1 r))
46 (setq deactivate-mark nil)))))
47
48; Add this to setup keybinding
49; (require 'rust-mode)
50; (define-key rust-mode-map (kbd "C-w") 'ra-extend-selection)
51; (define-key rust-mode-map (kbd "C-S-w") 'ra-shrink-selection)
52
53
54
55(defun ra--extend-selection (start end)
56 "Extend START END region to contain the encompassing syntactic construct."
57 (ra--freshen-cache start end)
58 (let* ((next-sel-idx (+ 1 (ra--cache-sel)))
59 (r (ra--cache-set-nth-sel next-sel-idx)))
60 (push-mark (nth 0 r) t t)
61 (goto-char (nth 1 r))
62 (setq deactivate-mark nil)))
63
64(defun ra--selections (start end)
65 "Get list of selections for START END from Rust analyzer."
66 (read (with-output-to-string
67 (call-process-region
68 (point-min) (point-max)
69 "ra_cli" nil standard-output nil
70 "extend-selection"
71 (number-to-string start)
72 (number-to-string end)))))
73
74(defun ra--freshen-cache (start end)
75 "Make selection cache up-to-date for current buffer state and START END."
76 (if (not (and
77 (= (buffer-modified-tick) (ra--cache-tick))
78 (equal `(,start ,end) (ra--cache-nth-sel (ra--cache-sel)))))
79 (ra--set-cache start end)))
80
81(defun ra--set-cache (start end)
82 "Set selections cache for current buffer state and START END."
83 (setq ra--selections-cache `(,(buffer-modified-tick) 0 ,(ra--selections start end))))
84
85(provide 'ra)
86;;; ra.el ends here