diff options
Diffstat (limited to 'codeless')
-rw-r--r-- | codeless/package.json | 7 | ||||
-rw-r--r-- | codeless/server/src/dispatch.rs | 23 | ||||
-rw-r--r-- | codeless/server/src/handlers.rs | 58 | ||||
-rw-r--r-- | codeless/server/src/main.rs | 50 | ||||
-rw-r--r-- | codeless/server/src/req.rs | 9 |
5 files changed, 118 insertions, 29 deletions
diff --git a/codeless/package.json b/codeless/package.json index 7a00f33ef..1df932db1 100644 --- a/codeless/package.json +++ b/codeless/package.json | |||
@@ -36,6 +36,13 @@ | |||
36 | "command": "libsyntax-rust.extendSelection", | 36 | "command": "libsyntax-rust.extendSelection", |
37 | "title": "Rust Extend Selection" | 37 | "title": "Rust Extend Selection" |
38 | } | 38 | } |
39 | ], | ||
40 | "keybindings": [ | ||
41 | { | ||
42 | "command": "libsyntax-rust.extendSelection", | ||
43 | "key": "ctrl+w", | ||
44 | "when": "editorTextFocus && editorLangId == rust" | ||
45 | } | ||
39 | ] | 46 | ] |
40 | } | 47 | } |
41 | } | 48 | } |
diff --git a/codeless/server/src/dispatch.rs b/codeless/server/src/dispatch.rs index 41437b62a..2da0996e3 100644 --- a/codeless/server/src/dispatch.rs +++ b/codeless/server/src/dispatch.rs | |||
@@ -52,7 +52,7 @@ impl<R: Request> Responder<R> | |||
52 | } | 52 | } |
53 | 53 | ||
54 | 54 | ||
55 | pub fn parse_request_as<R>(raw: RawRequest) -> Result<::std::result::Result<(R::Params, Responder<R>), RawRequest>> | 55 | fn parse_request_as<R>(raw: RawRequest) -> Result<::std::result::Result<(R::Params, Responder<R>), RawRequest>> |
56 | where | 56 | where |
57 | R: Request, | 57 | R: Request, |
58 | R::Params: DeserializeOwned, | 58 | R::Params: DeserializeOwned, |
@@ -71,6 +71,25 @@ pub fn parse_request_as<R>(raw: RawRequest) -> Result<::std::result::Result<(R:: | |||
71 | Ok(Ok((params, responder))) | 71 | Ok(Ok((params, responder))) |
72 | } | 72 | } |
73 | 73 | ||
74 | pub fn handle_request<R, F>(req: &mut Option<RawRequest>, f: F) -> Result<()> | ||
75 | where | ||
76 | R: Request, | ||
77 | R::Params: DeserializeOwned, | ||
78 | R::Result: Serialize, | ||
79 | F: FnOnce(R::Params, Responder<R>) -> Result<()> | ||
80 | { | ||
81 | match req.take() { | ||
82 | None => Ok(()), | ||
83 | Some(r) => match parse_request_as::<R>(r)? { | ||
84 | Ok((params, responder)) => f(params, responder), | ||
85 | Err(r) => { | ||
86 | *req = Some(r); | ||
87 | Ok(()) | ||
88 | }, | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | |||
74 | pub fn expect_request<R>(io: &mut Io, raw: RawRequest) -> Result<Option<(R::Params, Responder<R>)>> | 93 | pub fn expect_request<R>(io: &mut Io, raw: RawRequest) -> Result<Option<(R::Params, Responder<R>)>> |
75 | where | 94 | where |
76 | R: Request, | 95 | R: Request, |
@@ -87,7 +106,7 @@ pub fn expect_request<R>(io: &mut Io, raw: RawRequest) -> Result<Option<(R::Para | |||
87 | Ok(ret) | 106 | Ok(ret) |
88 | } | 107 | } |
89 | 108 | ||
90 | pub fn parse_notification_as<N>(raw: RawNotification) -> Result<::std::result::Result<N::Params, RawNotification>> | 109 | fn parse_notification_as<N>(raw: RawNotification) -> Result<::std::result::Result<N::Params, RawNotification>> |
91 | where | 110 | where |
92 | N: Notification, | 111 | N: Notification, |
93 | N::Params: DeserializeOwned, | 112 | N::Params: DeserializeOwned, |
diff --git a/codeless/server/src/handlers.rs b/codeless/server/src/handlers.rs index 3f257941a..5ee87a4dd 100644 --- a/codeless/server/src/handlers.rs +++ b/codeless/server/src/handlers.rs | |||
@@ -1,13 +1,61 @@ | |||
1 | use languageserver_types::{Range, Position}; | ||
1 | use libanalysis::World; | 2 | use libanalysis::World; |
2 | use libeditor; | 3 | use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit}; |
3 | use {req, Result}; | 4 | use {req, Result, FilePath}; |
4 | 5 | ||
5 | pub fn handle_syntax_tree( | 6 | pub fn handle_syntax_tree( |
6 | world: World, | 7 | world: World, |
7 | params: req::SyntaxTreeParams | 8 | params: req::SyntaxTreeParams, |
8 | ) -> Result<String> { | 9 | ) -> Result<String> { |
9 | let path = params.text_document.uri.to_file_path() | 10 | let path = params.text_document.file_path()?; |
10 | .map_err(|()| format_err!("invalid path"))?; | ||
11 | let file = world.file_syntax(&path)?; | 11 | let file = world.file_syntax(&path)?; |
12 | Ok(libeditor::syntax_tree(&file)) | 12 | Ok(libeditor::syntax_tree(&file)) |
13 | } | 13 | } |
14 | |||
15 | pub fn handle_extend_selection( | ||
16 | world: World, | ||
17 | params: req::ExtendSelectionParams, | ||
18 | ) -> Result<req::ExtendSelectionResult> { | ||
19 | let path = params.text_document.file_path()?; | ||
20 | let file = world.file_syntax(&path)?; | ||
21 | let line_index = world.file_line_index(&path)?; | ||
22 | let selections = params.selections.into_iter() | ||
23 | .map(|r| { | ||
24 | let r = to_text_range(&line_index, r); | ||
25 | let r = libeditor::extend_selection(&file, r).unwrap_or(r); | ||
26 | to_vs_range(&line_index, r) | ||
27 | }) | ||
28 | .collect(); | ||
29 | Ok(req::ExtendSelectionResult { selections }) | ||
30 | } | ||
31 | |||
32 | |||
33 | fn to_text_range(line_index: &LineIndex, range: Range) -> TextRange { | ||
34 | TextRange::from_to( | ||
35 | to_text_unit(line_index, range.start), | ||
36 | to_text_unit(line_index, range.end), | ||
37 | ) | ||
38 | } | ||
39 | |||
40 | fn to_text_unit(line_index: &LineIndex, position: Position) -> TextUnit { | ||
41 | // TODO: UTF-16 | ||
42 | let line_col = LineCol { | ||
43 | line: position.line as u32, | ||
44 | col: (position.character as u32).into(), | ||
45 | }; | ||
46 | line_index.offset(line_col) | ||
47 | } | ||
48 | |||
49 | |||
50 | fn to_vs_range(line_index: &LineIndex, range: TextRange) -> Range { | ||
51 | Range::new( | ||
52 | to_vs_position(line_index, range.start()), | ||
53 | to_vs_position(line_index, range.end()), | ||
54 | ) | ||
55 | } | ||
56 | |||
57 | fn to_vs_position(line_index: &LineIndex, offset: TextUnit) -> Position { | ||
58 | let line_col = line_index.line_col(offset); | ||
59 | // TODO: UTF-16 | ||
60 | Position::new(line_col.line as u64, u32::from(line_col.col) as u64) | ||
61 | } | ||
diff --git a/codeless/server/src/main.rs b/codeless/server/src/main.rs index 287d650fa..116abce1c 100644 --- a/codeless/server/src/main.rs +++ b/codeless/server/src/main.rs | |||
@@ -31,7 +31,7 @@ use languageserver_types::{TextDocumentItem, VersionedTextDocumentIdentifier, Te | |||
31 | 31 | ||
32 | use ::{ | 32 | use ::{ |
33 | io::{Io, RawMsg}, | 33 | io::{Io, RawMsg}, |
34 | handlers::handle_syntax_tree, | 34 | handlers::{handle_syntax_tree, handle_extend_selection}, |
35 | }; | 35 | }; |
36 | 36 | ||
37 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 37 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
@@ -153,34 +153,42 @@ fn main_loop( | |||
153 | 153 | ||
154 | match msg { | 154 | match msg { |
155 | RawMsg::Request(req) => { | 155 | RawMsg::Request(req) => { |
156 | let req = match dispatch::parse_request_as::<req::SyntaxTree>(req)? { | 156 | let mut req = Some(req); |
157 | Ok((params, resp)) => { | 157 | dispatch::handle_request::<req::SyntaxTree, _>(&mut req, |params, resp| { |
158 | let world = world.snapshot(); | 158 | let world = world.snapshot(); |
159 | let sender = sender.clone(); | 159 | let sender = sender.clone(); |
160 | pool.execute(move || { | 160 | pool.execute(move || { |
161 | let res: Result<String> = handle_syntax_tree(world, params); | 161 | let res = handle_syntax_tree(world, params); |
162 | sender.send(Box::new(|io: &mut Io| resp.response(io, res))) | 162 | sender.send(Box::new(|io: &mut Io| resp.response(io, res))) |
163 | }); | 163 | }); |
164 | continue; | 164 | Ok(()) |
165 | } | 165 | })?; |
166 | Err(req) => req, | 166 | dispatch::handle_request::<req::ExtendSelection, _>(&mut req, |params, resp| { |
167 | }; | 167 | let world = world.snapshot(); |
168 | 168 | let sender = sender.clone(); | |
169 | if let Some(((), resp)) = dispatch::expect_request::<req::Shutdown>(io, req)? { | 169 | pool.execute(move || { |
170 | info!("clean shutdown started"); | 170 | let res = handle_extend_selection(world, params); |
171 | sender.send(Box::new(|io: &mut Io| resp.response(io, res))) | ||
172 | }); | ||
173 | Ok(()) | ||
174 | })?; | ||
175 | dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { | ||
171 | resp.result(io, ())?; | 176 | resp.result(io, ())?; |
172 | return Ok(()); | 177 | Ok(()) |
178 | })?; | ||
179 | if let Some(req) = req { | ||
180 | error!("unknown method: {:?}", req); | ||
181 | dispatch::unknown_method(io, req)?; | ||
173 | } | 182 | } |
174 | } | 183 | } |
175 | RawMsg::Notification(not) => { | 184 | RawMsg::Notification(not) => { |
176 | use dispatch::handle_notification as h; | ||
177 | let mut not = Some(not); | 185 | let mut not = Some(not); |
178 | h::<req::DidOpenTextDocument, _>(&mut not, |params| { | 186 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { |
179 | let path = params.text_document.file_path()?; | 187 | let path = params.text_document.file_path()?; |
180 | world.change_overlay(path, Some(params.text_document.text)); | 188 | world.change_overlay(path, Some(params.text_document.text)); |
181 | Ok(()) | 189 | Ok(()) |
182 | })?; | 190 | })?; |
183 | h::<req::DidChangeTextDocument, _>(&mut not, |mut params| { | 191 | dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { |
184 | let path = params.text_document.file_path()?; | 192 | let path = params.text_document.file_path()?; |
185 | let text = params.content_changes.pop() | 193 | let text = params.content_changes.pop() |
186 | .ok_or_else(|| format_err!("empty changes"))? | 194 | .ok_or_else(|| format_err!("empty changes"))? |
@@ -188,7 +196,7 @@ fn main_loop( | |||
188 | world.change_overlay(path, Some(text)); | 196 | world.change_overlay(path, Some(text)); |
189 | Ok(()) | 197 | Ok(()) |
190 | })?; | 198 | })?; |
191 | h::<req::DidCloseTextDocument, _>(&mut not, |params| { | 199 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { |
192 | let path = params.text_document.file_path()?; | 200 | let path = params.text_document.file_path()?; |
193 | world.change_overlay(path, None); | 201 | world.change_overlay(path, None); |
194 | Ok(()) | 202 | Ok(()) |
diff --git a/codeless/server/src/req.rs b/codeless/server/src/req.rs index ee4a786c7..4e588159b 100644 --- a/codeless/server/src/req.rs +++ b/codeless/server/src/req.rs | |||
@@ -21,6 +21,12 @@ pub struct SyntaxTreeParams { | |||
21 | 21 | ||
22 | pub enum ExtendSelection {} | 22 | pub enum ExtendSelection {} |
23 | 23 | ||
24 | impl Request for ExtendSelection { | ||
25 | type Params = ExtendSelectionParams; | ||
26 | type Result = ExtendSelectionResult; | ||
27 | const METHOD: &'static str = "m/extendSelection"; | ||
28 | } | ||
29 | |||
24 | #[derive(Deserialize, Debug)] | 30 | #[derive(Deserialize, Debug)] |
25 | #[serde(rename_all = "camelCase")] | 31 | #[serde(rename_all = "camelCase")] |
26 | pub struct ExtendSelectionParams { | 32 | pub struct ExtendSelectionParams { |
@@ -28,7 +34,8 @@ pub struct ExtendSelectionParams { | |||
28 | pub selections: Vec<Range>, | 34 | pub selections: Vec<Range>, |
29 | } | 35 | } |
30 | 36 | ||
31 | 37 | #[derive(Serialize, Debug)] | |
38 | #[serde(rename_all = "camelCase")] | ||
32 | pub struct ExtendSelectionResult { | 39 | pub struct ExtendSelectionResult { |
33 | pub selections: Vec<Range>, | 40 | pub selections: Vec<Range>, |
34 | } | 41 | } |