aboutsummaryrefslogtreecommitdiff
path: root/codeless
diff options
context:
space:
mode:
Diffstat (limited to 'codeless')
-rw-r--r--codeless/package.json7
-rw-r--r--codeless/server/src/dispatch.rs23
-rw-r--r--codeless/server/src/handlers.rs58
-rw-r--r--codeless/server/src/main.rs50
-rw-r--r--codeless/server/src/req.rs9
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
55pub fn parse_request_as<R>(raw: RawRequest) -> Result<::std::result::Result<(R::Params, Responder<R>), RawRequest>> 55fn 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
74pub 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
74pub fn expect_request<R>(io: &mut Io, raw: RawRequest) -> Result<Option<(R::Params, Responder<R>)>> 93pub 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
90pub fn parse_notification_as<N>(raw: RawNotification) -> Result<::std::result::Result<N::Params, RawNotification>> 109fn 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 @@
1use languageserver_types::{Range, Position};
1use libanalysis::World; 2use libanalysis::World;
2use libeditor; 3use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit};
3use {req, Result}; 4use {req, Result, FilePath};
4 5
5pub fn handle_syntax_tree( 6pub 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
15pub 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
33fn 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
40fn 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
50fn 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
57fn 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
32use ::{ 32use ::{
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
37pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 37pub 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
22pub enum ExtendSelection {} 22pub enum ExtendSelection {}
23 23
24impl 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")]
26pub struct ExtendSelectionParams { 32pub 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")]
32pub struct ExtendSelectionResult { 39pub struct ExtendSelectionResult {
33 pub selections: Vec<Range>, 40 pub selections: Vec<Range>,
34} 41}