1 // Copyright 2017 The xi-editor Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! `PluginManager` handles launching, monitoring, and communicating with plugins.
16 
17 use std::collections::{BTreeMap, BTreeSet, HashSet};
18 use std::io;
19 use std::path::PathBuf;
20 use std::sync::{Arc, Mutex, Weak, MutexGuard};
21 
22 use std::path::Path;
23 use std::fmt::Debug;
24 
25 use serde::Serialize;
26 use serde_json::{self, Value};
27 
28 use xi_rpc::{RpcCtx, Handler, RemoteError};
29 use xi_trace::{self, trace_block, trace_block_payload};
30 
31 use tabs::{BufferIdentifier, ViewId, BufferContainerRef};
32 use config::Table;
33 
34 use super::{PluginCatalog, PluginRef, start_plugin_process, PluginPid};
35 use super::rpc::{PluginNotification, PluginRequest, PluginCommand,
36 PluginUpdate, PluginBufferInfo, ClientPluginInfo};
37 use super::manifest::{PluginActivation, Command};
38 
39 pub type PluginName = String;
40 type PluginGroup = BTreeMap<PluginName, PluginRef>;
41 
42 /// Manages plugin loading, activation, lifecycle, and dispatch.
43 pub struct PluginManager {
44     catalog: PluginCatalog,
45     /// Buffer-scoped plugins, by buffer
46     buffer_plugins: BTreeMap<BufferIdentifier, PluginGroup>,
47     global_plugins: PluginGroup,
48     launching_globals: BTreeSet<PluginName>,
49     buffers: BufferContainerRef,
50     next_id: usize,
51 }
52 
53 #[derive(Debug)]
54 /// The error type for plugin operations.
55 pub enum Error {
56     /// There was an error finding the buffer associated with a given view.
57     /// This probably means the buffer was destroyed while an RPC was in flight.
58     EditorMissing,
59     /// An error launching or communicating with a plugin process.
60     IoError(io::Error),
61     Other(String),
62 }
63 
64 // Note: In general I have adopted the pattern of putting non-threadsafe
65 // API in the 'inner' type of types with a ___Ref variant. Methods on the
66 // Ref variant should be minimal, and provide a threadsafe interface.
67 
68 impl PluginManager {
69 
70     /// Returns plugins available to this view.
get_available_plugins(&self, view_id: ViewId) -> Vec<ClientPluginInfo>71     pub fn get_available_plugins(&self, view_id: ViewId) -> Vec<ClientPluginInfo> {
72         self.catalog.iter_names().map(|name| {
73             let running = self.plugin_is_running(view_id, &name);
74             let name = name.clone();
75             ClientPluginInfo { name, running }
76         }).collect::<Vec<_>>()
77     }
78 
79     /// Passes an update from a buffer to all registered plugins.
update_plugins(&mut self, view_id: ViewId, update: PluginUpdate, undo_group: usize) -> Result<(), Error>80     fn update_plugins(&mut self, view_id: ViewId,
81                   update: PluginUpdate, undo_group: usize) -> Result<(), Error> {
82         let _t = trace_block("PluginManager::update_plugins", &["core"]);
83 
84         // find all running plugins for this buffer, and send them the update
85         let mut dead_plugins = Vec::new();
86 
87         if let Ok(running) = self.running_for_view(view_id) {
88             for (name, plugin) in running.iter().chain(self.global_plugins.iter()) {
89                 // check to see if plugins have crashed
90                 if plugin.is_dead() {
91                     dead_plugins.push((name.to_owned(), plugin.get_identifier()));
92                     continue;
93                 }
94 
95                 self.buffers.lock().editor_for_view_mut(view_id)
96                     .unwrap().increment_revs_in_flight();
97 
98                 let view_id = view_id.to_owned();
99                 let buffers = self.buffers.clone().to_weak();
100                 let mut plugin_ref = plugin.clone();
101 
102                 plugin.update(&update, move |response| {
103                     let buffers = match buffers.upgrade() {
104                         Some(b) => b,
105                         None => return,
106                     };
107 
108                     if response {
109                         buffers.lock().editor_for_view_mut(view_id)
110                             .unwrap().dec_revs_in_flight();
111                     }
112                 });
113             }
114         };
115         self.cleanup_dead(view_id, &dead_plugins);
116         self.buffers.lock().editor_for_view_mut(view_id).unwrap().dec_revs_in_flight();
117         Ok(())
118     }
119 
120     /// Sends a notification to groups of plugins.
notify_plugins<V>(&self, view_id: ViewId, only_globals: bool, method: &str, params: &V) where V: Serialize + Debug121     fn notify_plugins<V>(&self, view_id: ViewId,
122                          only_globals: bool, method: &str, params: &V)
123         where V: Serialize + Debug
124     {
125         let _t = trace_block("PluginManager::notify_plugins", &["core"]);
126         let params = serde_json::to_value(params)
127             .expect(&format!("bad notif params.\nmethod: {}\nparams: {:?}",
128                              method, params));
129         for plugin in self.global_plugins.values() {
130             plugin.rpc_notification(method, &params);
131         }
132         if !only_globals {
133             if let Ok(locals) = self.running_for_view(view_id) {
134                 for plugin in locals.values() {
135                     plugin.rpc_notification(method, &params);
136                 }
137             }
138         }
139     }
140 
toggle_tracing(&self, enabled: bool)141     fn toggle_tracing(&self, enabled: bool) {
142         self.global_plugins.values()
143             .for_each(|plug| {
144             plug.rpc_notification("tracing_config",
145                                   &json!({"enabled": enabled}))
146         });
147         self.buffer_plugins.values().flat_map(|group| group.values())
148             .for_each(|plug| {
149                 plug.rpc_notification("tracing_config",
150                                       &json!({"enabled": enabled}))
151             })
152     }
153 
request_trace(&self) -> Vec<Value>154     fn request_trace(&self) -> Vec<Value>
155     {
156         let _t = trace_block("PluginManager::request_trace", &["core"]);
157         let mut gathered_results = Vec::new();
158 
159         for plugin in self.global_plugins.values() {
160             match plugin.request_traces() {
161                 Ok(result) => gathered_results.push(result),
162                 Err(e) => warn!("trace {:?}, {:?}", plugin.get_identifier(), e),
163             }
164         }
165 
166         let mut processed_plugins = HashSet::new();
167 
168         for plugin in self.buffer_plugins.values().flat_map(|group| group.values()) {
169             // currently each buffer must have its own instance of a given plugin running.
170             assert!(processed_plugins.insert(plugin.get_identifier()));
171             match plugin.request_traces() {
172                 Ok(result) => gathered_results.push(result),
173                 Err(e) => warn!("trace {:?}, {:?}", plugin.get_identifier(), e),
174             }
175         }
176 
177         gathered_results
178     }
179 
dispatch_command(&self, view_id: ViewId, receiver: &str, method: &str, params: &Value)180     fn dispatch_command(&self, view_id: ViewId, receiver: &str,
181                         method: &str, params: &Value) {
182         let plugin_ref = self.running_for_view(view_id)
183             .ok()
184             .and_then(|r| r.get(receiver));
185 
186         match plugin_ref {
187             Some(plug) => {
188                 let inner = json!({"method": method, "params": params});
189                 plug.rpc_notification("custom_command", &inner);
190             }
191             None => {
192                 error!("missing plugin {} for command {}", receiver, method);
193             }
194         }
195     }
196 
197     /// Launches and initializes the named plugin.
start_plugin(&mut self, self_ref: &PluginManagerRef, view_id: ViewId, init_info: &PluginBufferInfo, plugin_name: &str, ) -> Result<(), Error>198     fn start_plugin(&mut self,
199                     self_ref: &PluginManagerRef,
200                     view_id: ViewId,
201                     init_info: &PluginBufferInfo,
202                     plugin_name: &str, ) -> Result<(), Error> {
203 
204         let _t = trace_block_payload("PluginManager::start_plugin", &["core"],
205                                      format!("{:?} {}", view_id, plugin_name));
206         // verify that this view_id is valid
207          let _ = self.running_for_view(view_id)?;
208          if self.plugin_is_running(view_id, plugin_name) {
209              return Err(Error::Other(format!("{} already running", plugin_name)));
210          }
211 
212         let plugin_id = self.next_plugin_id();
213         let plugin_desc = self.catalog.get_named(plugin_name)
214             .ok_or(Error::Other(format!("no plugin found with name {}", plugin_name)))?;
215 
216         let is_global = plugin_desc.is_global();
217         if is_global && !self.launching_globals.insert(plugin_name.to_owned()) {
218             return Err(Error::Other(format!("global {} has started", plugin_name)))
219         }
220 
221         let commands = plugin_desc.commands.clone();
222         let init_info = if is_global {
223             let buffers = self.buffers.lock();
224             let info = buffers.iter_editors()
225                 .map(|ed| ed.plugin_init_info().to_owned())
226                 .collect::<Vec<_>>();
227             info
228         } else {
229             vec![init_info.to_owned()]
230         };
231 
232         let me = self_ref.clone();
233         let plugin_name = plugin_name.to_owned();
234 
235         start_plugin_process(self_ref, &plugin_desc, plugin_id, move |result| {
236             match result {
237                 Ok(plugin_ref) => {
238                     if xi_trace::is_enabled() {
239                         plugin_ref.rpc_notification("tracing_config",
240                                                     &json!({"enabled": true}));
241                     }
242                     plugin_ref.initialize(&init_info);
243                     if is_global {
244                         me.lock().on_plugin_connect_global(&plugin_name, plugin_ref,
245                                                            commands);
246                     } else {
247                         me.lock().on_plugin_connect_local(view_id, &plugin_name,
248                                                           plugin_ref, commands);
249                     }
250                 }
251                 Err(err) => error!("failed to start plugin {}:\n {:?}",
252                                      plugin_name, err),
253             }
254         });
255         Ok(())
256     }
257 
258     /// Callback used to register a successfully launched local plugin.
on_plugin_connect_local(&mut self, view_id: ViewId, plugin_name: &str, plugin_ref: PluginRef, commands: Vec<Command>)259     fn on_plugin_connect_local(&mut self, view_id: ViewId,
260                               plugin_name: &str, plugin_ref: PluginRef,
261                               commands: Vec<Command>) {
262         // only add to our 'running' collection if the editor still exists
263         let is_running = match self.buffers.lock().editor_for_view(view_id) {
264             Some(ed) => {
265                 ed.plugin_started(view_id, plugin_name, &commands);
266                 true
267             }
268             None => false,
269         };
270         if is_running {
271             let _ = self.running_for_view_mut(view_id)
272                 .map(|running| running.insert(plugin_name.to_owned(), plugin_ref));
273         } else {
274             error!("launch of plugin {} failed, no buffer for view {}",
275                        plugin_name, view_id);
276             plugin_ref.shutdown();
277         }
278     }
279 
280     /// Callback used to register a successfully launched global plugin.
on_plugin_connect_global(&mut self, plugin_name: &str, plugin_ref: PluginRef, commands: Vec<Command>)281     fn on_plugin_connect_global(&mut self, plugin_name: &str,
282                                 plugin_ref: PluginRef, commands: Vec<Command>) {
283         {
284             let buffers = self.buffers.lock();
285             for ed in buffers.iter_editors() {
286                 ed.plugin_started(None, plugin_name, &commands);
287             }
288         }
289         self.launching_globals.remove(plugin_name);
290         self.global_plugins.insert(plugin_name.to_owned(), plugin_ref);
291     }
292 
stop_plugin(&mut self, view_id: ViewId, plugin_name: &str)293     fn stop_plugin(&mut self, view_id: ViewId, plugin_name: &str) {
294         let is_global = self.catalog.get_named(plugin_name).unwrap().is_global();
295         if is_global {
296             let plugin_ref = self.global_plugins.remove(plugin_name);
297             if let Some(plugin_ref) = plugin_ref {
298                 let plugin_id = plugin_ref.get_identifier();
299                 plugin_ref.shutdown();
300                 let mut buffers = self.buffers.lock();
301                 for ed in buffers.iter_editors_mut() {
302                     ed.plugin_stopped(None, plugin_name, plugin_id, 0);
303                 }
304             }
305         }
306         let plugin_ref = match self.running_for_view_mut(view_id) {
307             Ok(running) => running.remove(plugin_name),
308             Err(_) => None,
309         };
310 
311         if let Some(plugin_ref) = plugin_ref {
312             let plugin_id = plugin_ref.get_identifier();
313             plugin_ref.shutdown();
314             //TODO: should we notify now, or wait until we know this worked?
315             //can this fail? (yes.) How do we tell, and when do we kill the proc?
316             if let Some(ed) = self.buffers.lock().editor_for_view_mut(view_id) {
317                 ed.plugin_stopped(view_id, plugin_name, plugin_id, 0);
318             }
319         }
320     }
321 
322     /// Remove dead plugins, notifying editors as needed.
323     //TODO: this currently only runs after trying to update a plugin that has crashed
324     // during a previous update: that is, if a plugin crashes it isn't cleaned up
325     // immediately. If this is a problem, we should store crashes, and clean up in idle().
326     #[allow(non_snake_case)]
cleanup_dead(&mut self, view_id: ViewId, plugins: &[(PluginName, PluginPid)])327     fn cleanup_dead(&mut self, view_id: ViewId, plugins: &[(PluginName, PluginPid)]) {
328         //TODO: define exit codes, put them in an enum somewhere
329         let ABNORMAL_EXIT_CODE = 1;
330         for &(ref name, pid) in plugins.iter() {
331             let is_global = self.catalog.get_named(name).unwrap().is_global();
332             if is_global {
333                 {
334                     self.global_plugins.remove(name);
335                 }
336                 let mut buffers = self.buffers.lock();
337                 for ed in buffers.iter_editors_mut() {
338                     ed.plugin_stopped(None, name, pid, ABNORMAL_EXIT_CODE);
339                 }
340 
341             } else {
342                 let _ = self.running_for_view_mut(view_id)
343                     .map(|running| running.remove(name));
344                 self.buffers.lock().editor_for_view_mut(view_id).map(|ed|{
345                     ed.plugin_stopped(view_id, name, pid, ABNORMAL_EXIT_CODE);
346                 });
347             }
348         }
349     }
350 
351     // ====================================================================
352     // convenience functions
353     // ====================================================================
354 
buffer_for_view(&self, view_id: ViewId) -> Option<BufferIdentifier>355     fn buffer_for_view(&self, view_id: ViewId) -> Option<BufferIdentifier> {
356         self.buffers.buffer_for_view(view_id).map(|id| id.to_owned())
357     }
358 
next_plugin_id(&mut self) -> PluginPid359     fn next_plugin_id(&mut self) -> PluginPid {
360         self.next_id += 1;
361         PluginPid(self.next_id)
362     }
363 
plugin_is_running(&self, view_id: ViewId, plugin_name: &str) -> bool364     fn plugin_is_running(&self, view_id: ViewId, plugin_name: &str) -> bool {
365         self.buffer_for_view(view_id)
366             .and_then(|id| self.buffer_plugins.get(&id))
367             .map(|plugins| plugins.contains_key(plugin_name))
368             .unwrap_or_default() || self.global_plugins.contains_key(plugin_name)
369     }
370 
371     // TODO: we have a bunch of boilerplate around handling the rare case
372     // where we receive a command for some buffer which no longer exists.
373     // Maybe these two functions should return a Box<Iterator> of plugins,
374     // and if the buffer is missing just print a debug message and return
375     // an empty Iterator?
running_for_view(&self, view_id: ViewId) -> Result<&PluginGroup, Error>376     fn running_for_view(&self, view_id: ViewId) -> Result<&PluginGroup, Error> {
377         self.buffer_for_view(view_id)
378             .and_then(|id| self.buffer_plugins.get(&id))
379             .ok_or(Error::EditorMissing)
380     }
381 
running_for_view_mut(&mut self, view_id: ViewId) -> Result<&mut PluginGroup, Error>382     fn running_for_view_mut(&mut self, view_id: ViewId) -> Result<&mut PluginGroup, Error> {
383         let buffer_id = match self.buffer_for_view(view_id) {
384             Some(id) => Ok(id),
385             None => Err(Error::EditorMissing),
386         }?;
387         self.buffer_plugins.get_mut(&buffer_id)
388             .ok_or(Error::EditorMissing)
389     }
390 }
391 
392 /// Wrapper around an `Arc<Mutex<PluginManager>>`.
393 pub struct PluginManagerRef(Arc<Mutex<PluginManager>>);
394 
395 impl Clone for PluginManagerRef {
clone(&self) -> Self396     fn clone(&self) -> Self {
397         PluginManagerRef(self.0.clone())
398     }
399 }
400 
401 /// Wrapper around a `Weak<Mutex<PluginManager>>`
402 pub struct WeakPluginManagerRef(Weak<Mutex<PluginManager>>);
403 
404 impl WeakPluginManagerRef {
405     /// Upgrades the weak reference to an Arc, if possible.
406     ///
407     /// Returns `None` if the inner value has been deallocated.
upgrade(&self) -> Option<PluginManagerRef>408     pub fn upgrade(&self) -> Option<PluginManagerRef> {
409         match self.0.upgrade() {
410             Some(inner) => Some(PluginManagerRef(inner)),
411             None => None
412         }
413     }
414 }
415 
416 impl PluginManagerRef {
new(buffers: BufferContainerRef) -> Self417     pub fn new(buffers: BufferContainerRef) -> Self {
418         PluginManagerRef(Arc::new(Mutex::new(
419             PluginManager {
420                 // TODO: actually parse these from manifest files
421                 catalog: PluginCatalog::from_paths(Vec::new()),
422                 buffer_plugins: BTreeMap::new(),
423                 global_plugins: PluginGroup::new(),
424                 launching_globals: BTreeSet::new(),
425                 buffers,
426                 next_id: 0,
427             }
428         )))
429     }
430 
lock(&self) -> MutexGuard<PluginManager>431     pub fn lock(&self) -> MutexGuard<PluginManager> {
432         self.0.lock().unwrap()
433     }
434 
435     /// Creates a new `WeakPluginManagerRef`.
to_weak(&self) -> WeakPluginManagerRef436     pub fn to_weak(&self) -> WeakPluginManagerRef {
437         WeakPluginManagerRef(Arc::downgrade(&self.0))
438     }
439 
set_plugin_search_path(&self, paths: Vec<PathBuf>)440     pub fn set_plugin_search_path(&self, paths: Vec<PathBuf>) {
441         // hacky: we don't handle unloading plugins if the path changes.
442         // this assumes that we only set the path once, when we get
443         // `client_init`.
444         let mut inner = self.lock();
445         assert!(inner.catalog.iter().count() == 0);
446         inner.catalog = PluginCatalog::from_paths(paths);
447 
448     }
449 
toggle_tracing(&self, enabled: bool)450     pub fn toggle_tracing(&self, enabled: bool) {
451         self.lock().toggle_tracing(enabled)
452     }
453 
collect_trace(&self) -> Vec<Value>454     pub fn collect_trace(&self) -> Vec<Value> {
455         self.lock().request_trace()
456     }
457 
458     /// Called when a new buffer is created.
document_new(&self, view_id: ViewId, init_info: &PluginBufferInfo)459     pub fn document_new(&self, view_id: ViewId, init_info: &PluginBufferInfo) {
460         let available = self.lock().get_available_plugins(view_id);
461         {
462             let inner = self.lock();
463             let buffers = inner.buffers.lock();
464             buffers.editor_for_view(view_id)
465                 .map(|ed| { ed.available_plugins(view_id, &available) });
466         }
467 
468         if self.add_running_collection(view_id).is_ok() {
469             let to_start = self.activatable_plugins(view_id);
470             self.start_plugins(view_id, &init_info, &to_start);
471             self.lock().notify_plugins(view_id, true, "new_buffer", &json!({
472                 "buffer_info": vec![&init_info],
473             }));
474         }
475     }
476 
477     /// Called when a buffer is saved to a file.
document_did_save(&self, view_id: ViewId, path: &Path)478     pub fn document_did_save(&self, view_id: ViewId, path: &Path) {
479         self.lock().notify_plugins(view_id, false, "did_save", &json!({
480             "view_id": view_id,
481             "path": path,
482         }));
483     }
484 
485     /// Called when a buffer is closed.
document_close(&self, view_id: ViewId)486     pub fn document_close(&self, view_id: ViewId) {
487         let to_stop = self.lock().running_for_view(view_id)
488             .map(|running| {
489                 running.keys()
490                     .map(|k| k.to_owned())
491                     .collect::<Vec<_>>()
492             })
493             .unwrap_or_default();
494 
495         for plugin_name in to_stop {
496             self.stop_plugin(view_id, &plugin_name);
497         }
498         self.lock().notify_plugins(view_id, true, "did_close", &json!({
499             "view_id": view_id}));
500     }
501 
502     /// Called when a document's syntax definition has changed.
document_syntax_changed(&self, view_id: ViewId, init_info: PluginBufferInfo)503     pub fn document_syntax_changed(&self, view_id: ViewId, init_info: PluginBufferInfo) {
504         info!("document_syntax_changed {}", view_id);
505 
506         let start_keys = self.activatable_plugins(view_id).iter()
507             .map(|p| p.to_owned())
508             .collect::<BTreeSet<_>>();
509 
510         // stop currently running plugins that aren't on list
511         // TODO: don't stop plugins that weren't started by a syntax activation
512         for plugin_name in self.lock().running_for_view(view_id)
513             .unwrap()
514             .keys()
515             .filter(|k| !start_keys.contains(*k)) {
516                 self.stop_plugin(view_id, &plugin_name);
517             }
518 
519         //TODO: send syntax_changed notification before starting new plugins
520 
521         let to_run = start_keys.iter()
522             .filter(|k| !self.lock().plugin_is_running(view_id, k))
523             .map(|k| k.clone().to_owned())
524             .collect::<Vec<String>>();
525 
526         self.start_plugins(view_id, &init_info, &to_run);
527     }
528 
529     /// Notifies plugins of a user config change
document_config_changed(&self, view_id: ViewId, changes: &Table)530     pub fn document_config_changed(&self, view_id: ViewId,
531                                    changes: &Table) {
532         self.lock().notify_plugins(view_id, false, "config_changed",
533                                    &json!({"view_id": view_id, "changes": changes}));
534     }
535 
536     /// Launches and initializes the named plugin.
start_plugin(&self, view_id: ViewId, init_info: &PluginBufferInfo, plugin_name: &str) -> Result<(), Error>537     pub fn start_plugin(&self,
538                         view_id: ViewId,
539                         init_info: &PluginBufferInfo,
540                         plugin_name: &str) -> Result<(), Error> {
541         self.lock().start_plugin(self, view_id, init_info, plugin_name)
542     }
543 
544     /// Terminates and cleans up the named plugin.
stop_plugin(&self, view_id: ViewId, plugin_name: &str)545     pub fn stop_plugin(&self, view_id: ViewId, plugin_name: &str) {
546         self.lock().stop_plugin(view_id, plugin_name);
547     }
548 
549     /// Forward an update from a view to registered plugins.
update_plugins(&self, view_id: ViewId, update: PluginUpdate, undo_group: usize) -> Result<(), Error>550     pub fn update_plugins(&self, view_id: ViewId,
551                           update: PluginUpdate, undo_group: usize) -> Result<(), Error> {
552         self.lock().update_plugins(view_id, update, undo_group)
553     }
554 
555     /// Sends a custom notification to a running plugin
dispatch_command(&self, view_id: ViewId, receiver: &str, method: &str, params: &Value)556     pub fn dispatch_command(&self, view_id: ViewId, receiver: &str,
557                              method: &str, params: &Value) {
558         self.lock().dispatch_command(view_id, receiver, method, params);
559     }
560 
561     // ====================================================================
562     // implementation details
563     // ====================================================================
564 
565     /// Performs new buffer setup.
566     ///
567     /// Returns an error if `view_id` does not have an associated buffer,
568     /// which is possible if it was closed immediately after creation.
add_running_collection(&self, view_id: ViewId) -> Result<(),()>569     fn add_running_collection(&self, view_id: ViewId) -> Result<(),()> {
570         assert!(self.lock().running_for_view(view_id).is_err());
571         let buf_id = self.lock().buffer_for_view(view_id);
572         match buf_id {
573             Some(buf_id) => {
574                 self.lock().buffer_plugins.insert(buf_id, PluginGroup::new());
575                 Ok(())
576             }
577             None => Err(())
578         }
579     }
580 
581     /// Returns the plugins which want to activate for this view.
582     ///
583     /// That a plugin wants to activate does not mean it will be activated.
584     /// For instance, it could have already been disabled by user preference.
activatable_plugins(&self, view_id: ViewId) -> Vec<String>585     fn activatable_plugins(&self, view_id: ViewId) -> Vec<String> {
586         let inner = self.lock();
587         let syntax = inner.buffers.lock()
588             .editor_for_view(view_id)
589             .unwrap()
590             .get_syntax()
591             .to_owned();
592 
593         inner.catalog.filter(|plug_desc|{
594             plug_desc.activations.iter().any(|act|{
595                 match *act {
596                     PluginActivation::Autorun => true,
597                     PluginActivation::OnSyntax(ref other) if *other == syntax => true,
598                     _ => false,
599                 }
600             })
601         })
602         .iter()
603         .map(|desc| desc.name.to_owned())
604         .collect::<Vec<_>>()
605     }
606 
607     /// Batch run a group of plugins (as on creating a new view, for instance)
start_plugins(&self, view_id: ViewId, init_info: &PluginBufferInfo, plugin_names: &Vec<String>)608     fn start_plugins(&self, view_id: ViewId,
609                      init_info: &PluginBufferInfo, plugin_names: &Vec<String>) {
610         info!("starting plugins for {}", view_id);
611         for plugin_name in plugin_names.iter() {
612             match self.start_plugin(view_id, init_info, plugin_name) {
613                 Ok(_) => info!("starting plugin {}", plugin_name),
614                 Err(err) => error!("unable to start plugin {}, err: {:?}",
615                                        plugin_name, err),
616             }
617         }
618     }
619 }
620 
621 impl Handler for PluginManagerRef {
622     type Notification = PluginCommand<PluginNotification>;
623     type Request = PluginCommand<PluginRequest>;
624 
handle_notification(&mut self, _ctx: &RpcCtx, rpc: Self::Notification)625     fn handle_notification(&mut self, _ctx: &RpcCtx, rpc: Self::Notification) {
626         use self::PluginNotification::*;
627         let PluginCommand { view_id, plugin_id, cmd } = rpc;
628         let inner = self.lock();
629         let mut buffers = inner.buffers.lock();
630 
631         match cmd {
632             AddScopes { scopes } => buffers.editor_for_view_mut(view_id)
633                 .map(|ed| ed.plugin_add_scopes(plugin_id, scopes)),
634             UpdateSpans { start, len, spans, rev } => buffers.editor_for_view_mut(view_id)
635                 .map(|ed| ed.plugin_update_spans(plugin_id, start, len, spans, rev)),
636             Edit { edit } => buffers.editor_for_view_mut(view_id)
637                 .map(|ed| ed.plugin_edit_async(edit)),
638             Alert { msg } => buffers.editor_for_view(view_id)
639                 .map(|ed| ed.plugin_alert(&msg)),
640         };
641     }
642 
handle_request(&mut self, _ctx: &RpcCtx, rpc: Self::Request) -> Result<Value, RemoteError>643     fn handle_request(&mut self, _ctx: &RpcCtx, rpc: Self::Request) -> Result<Value, RemoteError> {
644         use self::PluginRequest::*;
645         let PluginCommand { view_id, cmd, .. } = rpc;
646         let inner = self.lock();
647         let buffers = inner.buffers.lock();
648 
649         let resp = match cmd {
650             LineCount => buffers.editor_for_view(view_id)
651                 .map(|ed| json!(ed.plugin_n_lines())),
652             GetData { start, unit, max_size, rev } => buffers.editor_for_view(view_id)
653                 .map(|ed| json!(ed.plugin_get_data(start, unit, max_size, rev))),
654             GetSelections => buffers.editor_for_view(view_id)
655                 .map(|ed| json!(ed.plugin_get_selections(view_id))),
656             };
657         resp.ok_or(RemoteError::custom(404,
658                                        "Missing editor",
659                                        json!({
660                                            "view_id": view_id,
661                                            "rpc": &cmd
662                                        })))
663     }
664 }
665