aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-03-16 14:09:04 +0000
committerGitHub2021-03-16 14:09:04 +0000
commit8dc0b18e35cdfdd76f435dcd43c1cfd5a3f0c7f7 (patch)
treea26c6025d45658b4d85d6917ea82489d6ba8fb2e
parentd8599f3a140eca7cd14f47e9b64f1ae9d829a0eb (diff)
parente3ec5e31ec005e33da4c848b4272e81a6d21a5f0 (diff)
Merge pull request #8 from helix-editor/gd
Goto
-rw-r--r--helix-lsp/src/client.rs94
-rw-r--r--helix-term/src/commands.rs106
-rw-r--r--helix-term/src/keymap.rs8
-rw-r--r--helix-term/test.rs36
-rw-r--r--helix-term/test.txt1000
-rw-r--r--helix-view/src/editor.rs10
6 files changed, 215 insertions, 1039 deletions
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index a9b7fe20..97e5cfad 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -582,4 +582,98 @@ impl Client {
Ok(response.unwrap_or_default())
}
+
+ async fn goto_request<
+ T: lsp::request::Request<
+ Params = lsp::GotoDefinitionParams,
+ Result = Option<lsp::GotoDefinitionResponse>,
+ >,
+ >(
+ &self,
+ text_document: lsp::TextDocumentIdentifier,
+ position: lsp::Position,
+ ) -> anyhow::Result<Vec<lsp::Location>> {
+ let params = lsp::GotoDefinitionParams {
+ text_document_position_params: lsp::TextDocumentPositionParams {
+ text_document,
+ position,
+ },
+ work_done_progress_params: lsp::WorkDoneProgressParams {
+ work_done_token: None,
+ },
+ partial_result_params: lsp::PartialResultParams {
+ partial_result_token: None,
+ },
+ };
+
+ let response = self.request::<T>(params).await?;
+
+ let items = match response {
+ Some(lsp::GotoDefinitionResponse::Scalar(location)) => vec![location],
+ Some(lsp::GotoDefinitionResponse::Array(locations)) => locations,
+ Some(lsp::GotoDefinitionResponse::Link(locations)) => locations
+ .into_iter()
+ .map(|location_link| lsp::Location {
+ uri: location_link.target_uri,
+ range: location_link.target_range,
+ })
+ .collect(),
+ None => Vec::new(),
+ };
+
+ Ok(items)
+ }
+
+ pub async fn goto_definition(
+ &self,
+ text_document: lsp::TextDocumentIdentifier,
+ position: lsp::Position,
+ ) -> anyhow::Result<Vec<lsp::Location>> {
+ self.goto_request::<lsp::request::GotoDefinition>(text_document, position)
+ .await
+ }
+
+ pub async fn goto_type_definition(
+ &self,
+ text_document: lsp::TextDocumentIdentifier,
+ position: lsp::Position,
+ ) -> anyhow::Result<Vec<lsp::Location>> {
+ self.goto_request::<lsp::request::GotoTypeDefinition>(text_document, position)
+ .await
+ }
+
+ pub async fn goto_implementation(
+ &self,
+ text_document: lsp::TextDocumentIdentifier,
+ position: lsp::Position,
+ ) -> anyhow::Result<Vec<lsp::Location>> {
+ self.goto_request::<lsp::request::GotoImplementation>(text_document, position)
+ .await
+ }
+
+ pub async fn goto_reference(
+ &self,
+ text_document: lsp::TextDocumentIdentifier,
+ position: lsp::Position,
+ ) -> anyhow::Result<Vec<lsp::Location>> {
+ let params = lsp::ReferenceParams {
+ text_document_position: lsp::TextDocumentPositionParams {
+ text_document,
+ position,
+ },
+ context: lsp::ReferenceContext {
+ include_declaration: true,
+ },
+ work_done_progress_params: lsp::WorkDoneProgressParams {
+ work_done_token: None,
+ },
+ partial_result_params: lsp::PartialResultParams {
+ partial_result_token: None,
+ },
+ };
+
+ let response = self.request::<lsp::request::References>(params).await?;
+
+ Ok(response.unwrap_or_default())
+ }
}
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 353d79cc..3e90fb63 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -13,6 +13,8 @@ use once_cell::sync::Lazy;
use crate::compositor::Compositor;
use crate::ui::{self, Popup, Prompt, PromptEvent};
+use std::path::PathBuf;
+
use helix_view::{
document::Mode,
view::{View, PADDING},
@@ -21,6 +23,8 @@ use helix_view::{
use crossterm::event::{KeyCode, KeyEvent};
+use helix_lsp::lsp;
+
pub struct Context<'a> {
pub count: usize,
pub editor: &'a mut Editor,
@@ -846,6 +850,108 @@ pub fn exit_select_mode(cx: &mut Context) {
cx.doc().mode = Mode::Normal;
}
+fn goto(cx: &mut Context, locations: Vec<lsp::Location>) {
+ let executor = cx.executor;
+ let doc = cx.doc();
+
+ doc.mode = Mode::Normal;
+
+ match locations.as_slice() {
+ [location] => {
+ cx.editor
+ .open(PathBuf::from(location.uri.path()), cx.executor);
+ let doc = cx.doc();
+ let definition_pos = location.range.start;
+ let new_pos = helix_lsp::util::lsp_pos_to_pos(doc.text().slice(..), definition_pos);
+ doc.set_selection(Selection::point(new_pos));
+ }
+ [] => (), // maybe show user message that no definition was found?
+ _locations => {
+ let mut picker = ui::Picker::new(
+ locations,
+ |item| {
+ let file = item.uri.as_str();
+ let line = item.range.start.line;
+ format!("{}:{}", file, line).into()
+ },
+ move |editor: &mut Editor, item| {
+ editor.open(PathBuf::from(item.uri.path()), &executor);
+ let mut doc = &mut editor.view_mut().doc;
+ let definition_pos = item.range.start;
+ let new_pos =
+ helix_lsp::util::lsp_pos_to_pos(doc.text().slice(..), definition_pos);
+ doc.set_selection(Selection::point(new_pos));
+ },
+ );
+ cx.push_layer(Box::new(picker));
+ }
+ }
+}
+
+pub fn goto_definition(cx: &mut Context) {
+ let doc = cx.doc();
+ let language_server = match doc.language_server.as_ref() {
+ Some(language_server) => language_server,
+ None => return,
+ };
+
+ // TODO: blocking here is not ideal
+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
+
+ // TODO: handle fails
+ let res =
+ smol::block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default();
+ goto(cx, res);
+}
+
+pub fn goto_type_definition(cx: &mut Context) {
+ let doc = cx.doc();
+ let language_server = match doc.language_server.as_ref() {
+ Some(language_server) => language_server,
+ None => return,
+ };
+
+ // TODO: blocking here is not ideal
+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
+
+ // TODO: handle fails
+ let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos))
+ .unwrap_or_default();
+ goto(cx, res);
+}
+
+pub fn goto_implementation(cx: &mut Context) {
+ let doc = cx.doc();
+ let language_server = match doc.language_server.as_ref() {
+ Some(language_server) => language_server,
+ None => return,
+ };
+
+ // TODO: blocking here is not ideal
+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
+
+ // TODO: handle fails
+ let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
+ .unwrap_or_default();
+ goto(cx, res);
+}
+
+pub fn goto_reference(cx: &mut Context) {
+ let doc = cx.doc();
+ let language_server = match doc.language_server.as_ref() {
+ Some(language_server) => language_server,
+ None => return,
+ };
+
+ // TODO: blocking here is not ideal
+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
+
+ // TODO: handle fails
+ let res =
+ smol::block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default();
+ goto(cx, res);
+}
+
// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
pub mod insert {
use super::*;
diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs
index 67490003..d9fe348f 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-term/src/keymap.rs
@@ -311,8 +311,12 @@ pub fn default() -> Keymaps {
code: KeyCode::Esc,
modifiers: Modifiers::NONE
} => commands::normal_mode as Command,
- key!('g') => commands::move_file_start as Command,
- key!('e') => commands::move_file_end as Command,
+ key!('g') => commands::move_file_start,
+ key!('e') => commands::move_file_end,
+ key!('d') => commands::goto_definition,
+ key!('t') => commands::goto_type_definition,
+ key!('r') => commands::goto_reference,
+ key!('i') => commands::goto_implementation,
),
)
}
diff --git a/helix-term/test.rs b/helix-term/test.rs
deleted file mode 100644
index 713c23d0..00000000
--- a/helix-term/test.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-pub struct TextArea {
- properties: Properties,
- frame: Rect,
-}
-
-impl Component for TextArea {
- type Message = ();
- type Properties = Properties;
-
- fn create(properties: Self::Properties, frame: Rect, _link: ComponentLink<Self>) -> Self {
- TextArea { properties, frame }
- }
-
- fn change<'a>(&'a mut self, properties: Self::Properties) -> ShouldRender {
- let a: &'static str = "ase";
- let q = 2u8;
- let q = 2 as u16;
- Some(0);
- true;
- self.properties = properties;
- ShouldRender::Yes
- }
-
- fn resize(&mut self, frame: Rect) -> ShouldRender {
- println!("hello world! \" test");
- self.frame = frame;
- ShouldRender::Yes
- }
-
- fn view(&self) -> Layout {
- let mut canvas = Canvas::new(self.frame.size);
- canvas.clear(self.properties.theme.text);
- self.draw_text(&mut canvas);
- canvas.into()
- }
-}
diff --git a/helix-term/test.txt b/helix-term/test.txt
deleted file mode 100644
index 11798245..00000000
--- a/helix-term/test.txt
+++ /dev/null
@@ -1,1000 +0,0 @@
-1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
-42
-43
-44
-45
-46
-47
-48
-49
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64
-65
-66
-67
-68
-69
-70
-71
-72
-73
-74
-75
-76
-77
-78
-79
-80
-81
-82
-83
-84
-85
-86
-87
-88
-89
-90
-91
-92
-93
-94
-95
-96
-97
-98
-99
-100
-101
-102
-103
-104
-105
-106
-107
-108
-109
-110
-111
-112
-113
-114
-115
-116
-117
-118
-119
-120
-121
-122
-123
-124
-125
-126
-127
-128
-129
-130
-131
-132
-133
-134
-135
-136
-137
-138
-139
-140
-141
-142
-143
-144
-145
-146
-147
-148
-149
-150
-151
-152
-153
-154
-155
-156
-157
-158
-159
-160
-161
-162
-163
-164
-165
-166
-167
-168
-169
-170
-171
-172
-173
-174
-175
-176
-177
-178
-179
-180
-181
-182
-183
-184
-185
-186
-187
-188
-189
-190
-191
-192
-193
-194
-195
-196
-197
-198
-199
-200
-201
-202
-203
-204
-205
-206
-207
-208
-209
-210
-211
-212
-213
-214
-215
-216
-217
-218
-219
-220
-221
-222
-223
-224
-225
-226
-227
-228
-229
-230
-231
-232
-233
-234
-235
-236
-237
-238
-239
-240
-241
-242
-243
-244
-245
-246
-247
-248
-249
-250
-251
-252
-253
-254
-255
-256
-257
-258
-259
-260
-261
-262
-263
-264
-265
-266
-267
-268
-269
-270
-271
-272
-273
-274
-275
-276
-277
-278
-279
-280
-281
-282
-283
-284
-285
-286
-287
-288
-289
-290
-291
-292
-293
-294
-295
-296
-297
-298
-299
-300
-301
-302
-303
-304
-305
-306
-307
-308
-309
-310
-311
-312
-313
-314
-315
-316
-317
-318
-319
-320
-321
-322
-323
-324
-325
-326
-327
-328
-329
-330
-331
-332
-333
-334
-335
-336
-337
-338
-339
-340
-341
-342
-343
-344
-345
-346
-347
-348
-349
-350
-351
-352
-353
-354
-355
-356
-357
-358
-359
-360
-361
-362
-363
-364
-365
-366
-367
-368
-369
-370
-371
-372
-373
-374
-375
-376
-377
-378
-379
-380
-381
-382
-383
-384
-385
-386
-387
-388
-389
-390
-391
-392
-393
-394
-395
-396
-397
-398
-399
-400
-401
-402
-403
-404
-405
-406
-407
-408
-409
-410
-411
-412
-413
-414
-415
-416
-417
-418
-419
-420
-421
-422
-423
-424
-425
-426
-427
-428
-429
-430
-431
-432
-433
-434
-435
-436
-437
-438
-439
-440
-441
-442
-443
-444
-445
-446
-447
-448
-449
-450
-451
-452
-453
-454
-455
-456
-457
-458
-459
-460
-461
-462
-463
-464
-465
-466
-467
-468
-469
-470
-471
-472
-473
-474
-475
-476
-477
-478
-479
-480
-481
-482
-483
-484
-485
-486
-487
-488
-489
-490
-491
-492
-493
-494
-495
-496
-497
-498
-499
-500
-501
-502
-503
-504
-505
-506
-507
-508
-509
-510
-511
-512
-513
-514
-515
-516
-517
-518
-519
-520
-521
-522
-523
-524
-525
-526
-527
-528
-529
-530
-531
-532
-533
-534
-535
-536
-537
-538
-539
-540
-541
-542
-543
-544
-545
-546
-547
-548
-549
-550
-551
-552
-553
-554
-555
-556
-557
-558
-559
-560
-561
-562
-563
-564
-565
-566
-567
-568
-569
-570
-571
-572
-573
-574
-575
-576
-577
-578
-579
-580
-581
-582
-583
-584
-585
-586
-587
-588
-589
-590
-591
-592
-593
-594
-595
-596
-597
-598
-599
-600
-601
-602
-603
-604
-605
-606
-607
-608
-609
-610
-611
-612
-613
-614
-615
-616
-617
-618
-619
-620
-621
-622
-623
-624
-625
-626
-627
-628
-629
-630
-631
-632
-633
-634
-635
-636
-637
-638
-639
-640
-641
-642
-643
-644
-645
-646
-647
-648
-649
-650
-651
-652
-653
-654
-655
-656
-657
-658
-659
-660
-661
-662
-663
-664
-665
-666
-667
-668
-669
-670
-671
-672
-673
-674
-675
-676
-677
-678
-679
-680
-681
-682
-683
-684
-685
-686
-687
-688
-689
-690
-691
-692
-693
-694
-695
-696
-697
-698
-699
-700
-701
-702
-703
-704
-705
-706
-707
-708
-709
-710
-711
-712
-713
-714
-715
-716
-717
-718
-719
-720
-721
-722
-723
-724
-725
-726
-727
-728
-729
-730
-731
-732
-733
-734
-735
-736
-737
-738
-739
-740
-741
-742
-743
-744
-745
-746
-747
-748
-749
-750
-751
-752
-753
-754
-755
-756
-757
-758
-759
-760
-761
-762
-763
-764
-765
-766
-767
-768
-769
-770
-771
-772
-773
-774
-775
-776
-777
-778
-779
-780
-781
-782
-783
-784
-785
-786
-787
-788
-789
-790
-791
-792
-793
-794
-795
-796
-797
-798
-799
-800
-801
-802
-803
-804
-805
-806
-807
-808
-809
-810
-811
-812
-813
-814
-815
-816
-817
-818
-819
-820
-821
-822
-823
-824
-825
-826
-827
-828
-829
-830
-831
-832
-833
-834
-835
-836
-837
-838
-839
-840
-841
-842
-843
-844
-845
-846
-847
-848
-849
-850
-851
-852
-853
-854
-855
-856
-857
-858
-859
-860
-861
-862
-863
-864
-865
-866
-867
-868
-869
-870
-871
-872
-873
-874
-875
-876
-877
-878
-879
-880
-881
-882
-883
-884
-885
-886
-887
-888
-889
-890
-891
-892
-893
-894
-895
-896
-897
-898
-899
-900
-901
-902
-903
-904
-905
-906
-907
-908
-909
-910
-911
-912
-913
-914
-915
-916
-917
-918
-919
-920
-921
-922
-923
-924
-925
-926
-927
-928
-929
-930
-931
-932
-933
-934
-935
-936
-937
-938
-939
-940
-941
-942
-943
-944
-945
-946
-947
-948
-949
-950
-951
-952
-953
-954
-955
-956
-957
-958
-959
-960
-961
-962
-963
-964
-965
-966
-967
-968
-969
-970
-971
-972
-973
-974
-975
-976
-977
-978
-979
-980
-981
-982
-983
-984
-985
-986
-987
-988
-989
-990
-991
-992
-993
-994
-995
-996
-997
-998
-999
-1000
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index b04a07dd..5c94df27 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -33,7 +33,15 @@ impl Editor {
}
pub fn open(&mut self, path: PathBuf, executor: &smol::Executor) -> Result<(), Error> {
- // TODO: try to find an open view/buffer first
+ let existing_view = self
+ .tree
+ .views()
+ .find(|(view, _)| view.doc.path() == Some(&path));
+
+ if let Some((view, _)) = existing_view {
+ self.tree.focus = view.id;
+ return Ok(());
+ }
let mut doc = Document::load(path, self.theme.scopes())?;