@@ -14,7 +14,7 @@ use helix_view::{
14
14
graphics:: Rect ,
15
15
theme,
16
16
tree:: Layout ,
17
- Align , Editor ,
17
+ Align , ClientId , Editor ,
18
18
} ;
19
19
use serde_json:: json;
20
20
use tui:: backend:: Backend ;
@@ -62,6 +62,7 @@ pub struct Application {
62
62
compositor : Compositor ,
63
63
terminal : Terminal ,
64
64
pub editor : Editor ,
65
+ pub client_id : ClientId ,
65
66
66
67
config : Arc < ArcSwap < Config > > ,
67
68
@@ -115,14 +116,15 @@ impl Application {
115
116
let config = Arc :: new ( ArcSwap :: from_pointee ( config) ) ;
116
117
let handlers = handlers:: setup ( config. clone ( ) ) ;
117
118
let mut editor = Editor :: new (
118
- area,
119
119
Arc :: new ( theme_loader) ,
120
120
Arc :: new ( ArcSwap :: from_pointee ( lang_loader) ) ,
121
121
Arc :: new ( Map :: new ( Arc :: clone ( & config) , |config : & Config | {
122
122
& config. editor
123
123
} ) ) ,
124
124
handlers,
125
125
) ;
126
+ let client_id = editor. add_client ( area) ;
127
+ editor. most_recent_client_id = Some ( client_id) ;
126
128
Self :: load_configured_theme ( & mut editor, & config. load ( ) ) ;
127
129
128
130
let keys = Box :: new ( Map :: new ( Arc :: clone ( & config) , |config : & Config | {
@@ -133,15 +135,15 @@ impl Application {
133
135
134
136
if args. load_tutor {
135
137
let path = helix_loader:: runtime_file ( Path :: new ( "tutor" ) ) ;
136
- editor. open ( & path, Action :: VerticalSplit ) ?;
138
+ editor. open ( client_id , & path, Action :: VerticalSplit ) ?;
137
139
// Unset path to prevent accidentally saving to the original tutor file.
138
- doc_mut ! ( editor) . set_path ( None ) ;
140
+ doc_mut ! ( editor, client_id ) . set_path ( None ) ;
139
141
} else if !args. files . is_empty ( ) {
140
142
let mut files_it = args. files . into_iter ( ) . peekable ( ) ;
141
143
142
144
// If the first file is a directory, skip it and open a picker
143
145
if let Some ( ( first, _) ) = files_it. next_if ( |( p, _) | p. is_dir ( ) ) {
144
- let picker = ui:: file_picker ( & editor, first) ;
146
+ let picker = ui:: file_picker ( & editor, client_id , first) ;
145
147
compositor. push ( Box :: new ( overlaid ( picker) ) ) ;
146
148
}
147
149
@@ -167,7 +169,7 @@ impl Application {
167
169
None => Action :: Load ,
168
170
} ;
169
171
let old_id = editor. document_id_by_path ( & file) ;
170
- let doc_id = match editor. open ( & file, action) {
172
+ let doc_id = match editor. open ( client_id , & file, action) {
171
173
// Ignore irregular files during application init.
172
174
Err ( DocumentOpenError :: IrregularFile ) => {
173
175
nr_of_files -= 1 ;
@@ -185,8 +187,8 @@ impl Application {
185
187
// NOTE: this isn't necessarily true anymore. If
186
188
// `--vsplit` or `--hsplit` are used, the file which is
187
189
// opened last is focused on.
188
- let view_id = editor. tree . focus ;
189
- let doc = doc_mut ! ( editor, & doc_id) ;
190
+ let view_id = client ! ( editor, client_id ) . tree . focus ;
191
+ let doc = doc_with_id_mut ! ( editor, & doc_id) ;
190
192
let selection = pos
191
193
. into_iter ( )
192
194
. map ( |coords| {
@@ -199,7 +201,7 @@ impl Application {
199
201
200
202
// if all files were invalid, replace with empty buffer
201
203
if nr_of_files == 0 {
202
- editor. new_file ( Action :: VerticalSplit ) ;
204
+ editor. new_file ( client_id , Action :: VerticalSplit ) ;
203
205
} else {
204
206
editor. set_status ( format ! (
205
207
"Loaded {} file{}." ,
@@ -208,18 +210,18 @@ impl Application {
208
210
) ) ;
209
211
// align the view to center after all files are loaded,
210
212
// does not affect views without pos since it is at the top
211
- let ( view, doc) = current ! ( editor) ;
213
+ let ( _client , view, doc) = current ! ( editor, client_id ) ;
212
214
align_view ( doc, view, Align :: Center ) ;
213
215
}
214
216
} else {
215
- editor. new_file ( Action :: VerticalSplit ) ;
217
+ editor. new_file ( client_id , Action :: VerticalSplit ) ;
216
218
}
217
219
} else if stdin ( ) . is_tty ( ) || cfg ! ( feature = "integration" ) {
218
- editor. new_file ( Action :: VerticalSplit ) ;
220
+ editor. new_file ( client_id , Action :: VerticalSplit ) ;
219
221
} else {
220
222
editor
221
- . new_file_from_stdin ( Action :: VerticalSplit )
222
- . unwrap_or_else ( |_| editor. new_file ( Action :: VerticalSplit ) ) ;
223
+ . new_file_from_stdin ( client_id , Action :: VerticalSplit )
224
+ . unwrap_or_else ( |_| editor. new_file ( client_id , Action :: VerticalSplit ) ) ;
223
225
}
224
226
225
227
#[ cfg( windows) ]
@@ -238,6 +240,7 @@ impl Application {
238
240
compositor,
239
241
terminal,
240
242
editor,
243
+ client_id,
241
244
config,
242
245
signals,
243
246
jobs : Jobs :: new ( ) ,
@@ -255,6 +258,7 @@ impl Application {
255
258
256
259
let mut cx = crate :: compositor:: Context {
257
260
editor : & mut self . editor ,
261
+ client_id : self . client_id ,
258
262
jobs : & mut self . jobs ,
259
263
scroll : None ,
260
264
} ;
@@ -272,7 +276,7 @@ impl Application {
272
276
let surface = self . terminal . current_buffer_mut ( ) ;
273
277
274
278
self . compositor . render ( area, surface, & mut cx) ;
275
- let ( pos, kind) = self . compositor . cursor ( area, & self . editor ) ;
279
+ let ( pos, kind) = self . compositor . cursor ( area, & self . editor , self . client_id ) ;
276
280
// reset cursor cache
277
281
self . editor . cursor_cache . reset ( ) ;
278
282
@@ -380,8 +384,8 @@ impl Application {
380
384
381
385
// reset view position in case softwrap was enabled/disabled
382
386
let scrolloff = self . editor . config ( ) . scrolloff ;
383
- for ( view, _ ) in self . editor . tree . views ( ) {
384
- let doc = doc_mut ! ( self . editor, & view. doc) ;
387
+ for view in self . editor . views . iter ( ) {
388
+ let doc = doc_with_id_mut ! ( self . editor, & view. doc) ;
385
389
view. ensure_cursor_in_view ( doc, scrolloff) ;
386
390
}
387
391
}
@@ -534,6 +538,7 @@ impl Application {
534
538
pub async fn handle_idle_timeout ( & mut self ) {
535
539
let mut cx = crate :: compositor:: Context {
536
540
editor : & mut self . editor ,
541
+ client_id : ClientId :: default ( ) ,
537
542
jobs : & mut self . jobs ,
538
543
scroll : None ,
539
544
} ;
@@ -613,7 +618,7 @@ impl Application {
613
618
helix_event:: request_redraw ( ) ;
614
619
}
615
620
EditorEvent :: DebuggerEvent ( ( id, payload) ) => {
616
- let needs_render = self . editor . handle_debugger_message ( id, payload) . await ;
621
+ let needs_render = self . editor . handle_debugger_message ( self . editor . most_recent_client_id . unwrap ( ) , id, payload) . await ;
617
622
if needs_render {
618
623
self . render ( ) . await ;
619
624
}
@@ -638,6 +643,7 @@ impl Application {
638
643
pub async fn handle_terminal_events ( & mut self , event : std:: io:: Result < CrosstermEvent > ) {
639
644
let mut cx = crate :: compositor:: Context {
640
645
editor : & mut self . editor ,
646
+ client_id : self . client_id ,
641
647
jobs : & mut self . jobs ,
642
648
scroll : None ,
643
649
} ;
@@ -916,9 +922,11 @@ impl Application {
916
922
let language_server = language_server ! ( ) ;
917
923
if language_server. is_initialized ( ) {
918
924
let offset_encoding = language_server. offset_encoding ( ) ;
919
- let res = self
920
- . editor
921
- . apply_workspace_edit ( offset_encoding, & params. edit ) ;
925
+ let res = self . editor . apply_workspace_edit (
926
+ self . editor . most_recent_client_id . unwrap ( ) ,
927
+ offset_encoding,
928
+ & params. edit ,
929
+ ) ;
922
930
923
931
Ok ( json ! ( lsp:: ApplyWorkspaceEditResponse {
924
932
applied: res. is_ok( ) ,
@@ -1072,19 +1080,20 @@ impl Application {
1072
1080
_ => helix_view:: editor:: Action :: VerticalSplit ,
1073
1081
} ;
1074
1082
1075
- let doc_id = match self . editor . open ( path, action) {
1083
+ let most_recent_client = self . editor . most_recent_client_id . unwrap ( ) ;
1084
+ let doc_id = match self . editor . open ( most_recent_client, path, action) {
1076
1085
Ok ( id) => id,
1077
1086
Err ( err) => {
1078
1087
log:: error!( "failed to open path: {:?}: {:?}" , uri, err) ;
1079
1088
return lsp:: ShowDocumentResult { success : false } ;
1080
1089
}
1081
1090
} ;
1082
1091
1083
- let doc = doc_mut ! ( self . editor, & doc_id) ;
1092
+ let doc = doc_with_id_mut ! ( self . editor, & doc_id) ;
1084
1093
if let Some ( range) = selection {
1085
1094
// TODO: convert inside server
1086
1095
if let Some ( new_range) = lsp_range_to_range ( doc. text ( ) , range, offset_encoding) {
1087
- let view = view_mut ! ( self . editor) ;
1096
+ let view = client_view_mut ! ( self . editor, most_recent_client ) ;
1088
1097
1089
1098
// we flip the range so that the cursor sits on the start of the symbol
1090
1099
// (for example start of the function).
0 commit comments