573919201805e02be6e4d7f28140a46b969ad9e9676617bb4bd36d3c62db9c35d529bd4a05aefc5877cd09666d0df8ca89ce60331291d3e313e07fb52929da 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  6. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  7. return new (P || (P = Promise))(function (resolve, reject) {
  8. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  9. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  10. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  11. step((generator = generator.apply(thisArg, _arguments || [])).next());
  12. });
  13. };
  14. import { $, append, clearNode, createStyleSheet, h, hasParentWithClass } from '../../dom.js';
  15. import { DomEmitter } from '../../event.js';
  16. import { StandardKeyboardEvent } from '../../keyboardEvent.js';
  17. import { ActionBar } from '../actionbar/actionbar.js';
  18. import { FindInput } from '../findinput/findInput.js';
  19. import { ElementsDragAndDropData } from '../list/listView.js';
  20. import { isButton, isInputElement, isMonacoEditor, List, MouseController } from '../list/listWidget.js';
  21. import { Toggle } from '../toggle/toggle.js';
  22. import { getVisibleState, isFilterResult } from './indexTreeModel.js';
  23. import { TreeMouseEventTarget } from './tree.js';
  24. import { Action } from '../../../common/actions.js';
  25. import { distinct, equals, range } from '../../../common/arrays.js';
  26. import { disposableTimeout, timeout } from '../../../common/async.js';
  27. import { Codicon } from '../../../common/codicons.js';
  28. import { SetMap } from '../../../common/collections.js';
  29. import { Emitter, Event, EventBufferer, Relay } from '../../../common/event.js';
  30. import { fuzzyScore, FuzzyScore } from '../../../common/filters.js';
  31. import { Disposable, DisposableStore, dispose, toDisposable } from '../../../common/lifecycle.js';
  32. import { clamp } from '../../../common/numbers.js';
  33. import { isNumber } from '../../../common/types.js';
  34. import './media/tree.css';
  35. import { localize } from '../../../../nls.js';
  36. class TreeElementsDragAndDropData extends ElementsDragAndDropData {
  37. constructor(data) {
  38. super(data.elements.map(node => node.element));
  39. this.data = data;
  40. }
  41. }
  42. function asTreeDragAndDropData(data) {
  43. if (data instanceof ElementsDragAndDropData) {
  44. return new TreeElementsDragAndDropData(data);
  45. }
  46. return data;
  47. }
  48. class TreeNodeListDragAndDrop {
  49. constructor(modelProvider, dnd) {
  50. this.modelProvider = modelProvider;
  51. this.dnd = dnd;
  52. this.autoExpandDisposable = Disposable.None;
  53. }
  54. getDragURI(node) {
  55. return this.dnd.getDragURI(node.element);
  56. }
  57. getDragLabel(nodes, originalEvent) {
  58. if (this.dnd.getDragLabel) {
  59. return this.dnd.getDragLabel(nodes.map(node => node.element), originalEvent);
  60. }
  61. return undefined;
  62. }
  63. onDragStart(data, originalEvent) {
  64. var _a, _b;
  65. (_b = (_a = this.dnd).onDragStart) === null || _b === void 0 ? void 0 : _b.call(_a, asTreeDragAndDropData(data), originalEvent);
  66. }
  67. onDragOver(data, targetNode, targetIndex, originalEvent, raw = true) {
  68. const result = this.dnd.onDragOver(asTreeDragAndDropData(data), targetNode && targetNode.element, targetIndex, originalEvent);
  69. const didChangeAutoExpandNode = this.autoExpandNode !== targetNode;
  70. if (didChangeAutoExpandNode) {
  71. this.autoExpandDisposable.dispose();
  72. this.autoExpandNode = targetNode;
  73. }
  74. if (typeof targetNode === 'undefined') {
  75. return result;
  76. }
  77. if (didChangeAutoExpandNode && typeof result !== 'boolean' && result.autoExpand) {
  78. this.autoExpandDisposable = disposableTimeout(() => {
  79. const model = this.modelProvider();
  80. const ref = model.getNodeLocation(targetNode);
  81. if (model.isCollapsed(ref)) {
  82. model.setCollapsed(ref, false);
  83. }
  84. this.autoExpandNode = undefined;
  85. }, 500);
  86. }
  87. if (typeof result === 'boolean' || !result.accept || typeof result.bubble === 'undefined' || result.feedback) {
  88. if (!raw) {
  89. const accept = typeof result === 'boolean' ? result : result.accept;
  90. const effect = typeof result === 'boolean' ? undefined : result.effect;
  91. return { accept, effect, feedback: [targetIndex] };
  92. }
  93. return result;
  94. }
  95. if (result.bubble === 1 /* TreeDragOverBubble.Up */) {
  96. const model = this.modelProvider();
  97. const ref = model.getNodeLocation(targetNode);
  98. const parentRef = model.getParentNodeLocation(ref);
  99. const parentNode = model.getNode(parentRef);
  100. const parentIndex = parentRef && model.getListIndex(parentRef);
  101. return this.onDragOver(data, parentNode, parentIndex, originalEvent, false);
  102. }
  103. const model = this.modelProvider();
  104. const ref = model.getNodeLocation(targetNode);
  105. const start = model.getListIndex(ref);
  106. const length = model.getListRenderCount(ref);
  107. return Object.assign(Object.assign({}, result), { feedback: range(start, start + length) });
  108. }
  109. drop(data, targetNode, targetIndex, originalEvent) {
  110. this.autoExpandDisposable.dispose();
  111. this.autoExpandNode = undefined;
  112. this.dnd.drop(asTreeDragAndDropData(data), targetNode && targetNode.element, targetIndex, originalEvent);
  113. }
  114. onDragEnd(originalEvent) {
  115. var _a, _b;
  116. (_b = (_a = this.dnd).onDragEnd) === null || _b === void 0 ? void 0 : _b.call(_a, originalEvent);
  117. }
  118. }
  119. function asListOptions(modelProvider, options) {
  120. return options && Object.assign(Object.assign({}, options), { identityProvider: options.identityProvider && {
  121. getId(el) {
  122. return options.identityProvider.getId(el.element);
  123. }
  124. }, dnd: options.dnd && new TreeNodeListDragAndDrop(modelProvider, options.dnd), multipleSelectionController: options.multipleSelectionController && {
  125. isSelectionSingleChangeEvent(e) {
  126. return options.multipleSelectionController.isSelectionSingleChangeEvent(Object.assign(Object.assign({}, e), { element: e.element }));
  127. },
  128. isSelectionRangeChangeEvent(e) {
  129. return options.multipleSelectionController.isSelectionRangeChangeEvent(Object.assign(Object.assign({}, e), { element: e.element }));
  130. }
  131. }, accessibilityProvider: options.accessibilityProvider && Object.assign(Object.assign({}, options.accessibilityProvider), { getSetSize(node) {
  132. const model = modelProvider();
  133. const ref = model.getNodeLocation(node);
  134. const parentRef = model.getParentNodeLocation(ref);
  135. const parentNode = model.getNode(parentRef);
  136. return parentNode.visibleChildrenCount;
  137. },
  138. getPosInSet(node) {
  139. return node.visibleChildIndex + 1;
  140. }, isChecked: options.accessibilityProvider && options.accessibilityProvider.isChecked ? (node) => {
  141. return options.accessibilityProvider.isChecked(node.element);
  142. } : undefined, getRole: options.accessibilityProvider && options.accessibilityProvider.getRole ? (node) => {
  143. return options.accessibilityProvider.getRole(node.element);
  144. } : () => 'treeitem', getAriaLabel(e) {
  145. return options.accessibilityProvider.getAriaLabel(e.element);
  146. },
  147. getWidgetAriaLabel() {
  148. return options.accessibilityProvider.getWidgetAriaLabel();
  149. }, getWidgetRole: options.accessibilityProvider && options.accessibilityProvider.getWidgetRole ? () => options.accessibilityProvider.getWidgetRole() : () => 'tree', getAriaLevel: options.accessibilityProvider && options.accessibilityProvider.getAriaLevel ? (node) => options.accessibilityProvider.getAriaLevel(node.element) : (node) => {
  150. return node.depth;
  151. }, getActiveDescendantId: options.accessibilityProvider.getActiveDescendantId && (node => {
  152. return options.accessibilityProvider.getActiveDescendantId(node.element);
  153. }) }), keyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && Object.assign(Object.assign({}, options.keyboardNavigationLabelProvider), { getKeyboardNavigationLabel(node) {
  154. return options.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(node.element);
  155. } }) });
  156. }
  157. export class ComposedTreeDelegate {
  158. constructor(delegate) {
  159. this.delegate = delegate;
  160. }
  161. getHeight(element) {
  162. return this.delegate.getHeight(element.element);
  163. }
  164. getTemplateId(element) {
  165. return this.delegate.getTemplateId(element.element);
  166. }
  167. hasDynamicHeight(element) {
  168. return !!this.delegate.hasDynamicHeight && this.delegate.hasDynamicHeight(element.element);
  169. }
  170. setDynamicHeight(element, height) {
  171. var _a, _b;
  172. (_b = (_a = this.delegate).setDynamicHeight) === null || _b === void 0 ? void 0 : _b.call(_a, element.element, height);
  173. }
  174. }
  175. export var RenderIndentGuides;
  176. (function (RenderIndentGuides) {
  177. RenderIndentGuides["None"] = "none";
  178. RenderIndentGuides["OnHover"] = "onHover";
  179. RenderIndentGuides["Always"] = "always";
  180. })(RenderIndentGuides || (RenderIndentGuides = {}));
  181. class EventCollection {
  182. constructor(onDidChange, _elements = []) {
  183. this._elements = _elements;
  184. this.disposables = new DisposableStore();
  185. this.onDidChange = Event.forEach(onDidChange, elements => this._elements = elements, this.disposables);
  186. }
  187. get elements() {
  188. return this._elements;
  189. }
  190. dispose() {
  191. this.disposables.dispose();
  192. }
  193. }
  194. class TreeRenderer {
  195. constructor(renderer, modelProvider, onDidChangeCollapseState, activeNodes, options = {}) {
  196. var _a;
  197. this.renderer = renderer;
  198. this.modelProvider = modelProvider;
  199. this.activeNodes = activeNodes;
  200. this.renderedElements = new Map();
  201. this.renderedNodes = new Map();
  202. this.indent = TreeRenderer.DefaultIndent;
  203. this.hideTwistiesOfChildlessElements = false;
  204. this.shouldRenderIndentGuides = false;
  205. this.renderedIndentGuides = new SetMap();
  206. this.activeIndentNodes = new Set();
  207. this.indentGuidesDisposable = Disposable.None;
  208. this.disposables = new DisposableStore();
  209. this.templateId = renderer.templateId;
  210. this.updateOptions(options);
  211. Event.map(onDidChangeCollapseState, e => e.node)(this.onDidChangeNodeTwistieState, this, this.disposables);
  212. (_a = renderer.onDidChangeTwistieState) === null || _a === void 0 ? void 0 : _a.call(renderer, this.onDidChangeTwistieState, this, this.disposables);
  213. }
  214. updateOptions(options = {}) {
  215. if (typeof options.indent !== 'undefined') {
  216. this.indent = clamp(options.indent, 0, 40);
  217. }
  218. if (typeof options.renderIndentGuides !== 'undefined') {
  219. const shouldRenderIndentGuides = options.renderIndentGuides !== RenderIndentGuides.None;
  220. if (shouldRenderIndentGuides !== this.shouldRenderIndentGuides) {
  221. this.shouldRenderIndentGuides = shouldRenderIndentGuides;
  222. this.indentGuidesDisposable.dispose();
  223. if (shouldRenderIndentGuides) {
  224. const disposables = new DisposableStore();
  225. this.activeNodes.onDidChange(this._onDidChangeActiveNodes, this, disposables);
  226. this.indentGuidesDisposable = disposables;
  227. this._onDidChangeActiveNodes(this.activeNodes.elements);
  228. }
  229. }
  230. }
  231. if (typeof options.hideTwistiesOfChildlessElements !== 'undefined') {
  232. this.hideTwistiesOfChildlessElements = options.hideTwistiesOfChildlessElements;
  233. }
  234. }
  235. renderTemplate(container) {
  236. const el = append(container, $('.monaco-tl-row'));
  237. const indent = append(el, $('.monaco-tl-indent'));
  238. const twistie = append(el, $('.monaco-tl-twistie'));
  239. const contents = append(el, $('.monaco-tl-contents'));
  240. const templateData = this.renderer.renderTemplate(contents);
  241. return { container, indent, twistie, indentGuidesDisposable: Disposable.None, templateData };
  242. }
  243. renderElement(node, index, templateData, height) {
  244. if (typeof height === 'number') {
  245. this.renderedNodes.set(node, { templateData, height });
  246. this.renderedElements.set(node.element, node);
  247. }
  248. const indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent;
  249. templateData.twistie.style.paddingLeft = `${indent}px`;
  250. templateData.indent.style.width = `${indent + this.indent - 16}px`;
  251. this.renderTwistie(node, templateData);
  252. if (typeof height === 'number') {
  253. this.renderIndentGuides(node, templateData);
  254. }
  255. this.renderer.renderElement(node, index, templateData.templateData, height);
  256. }
  257. disposeElement(node, index, templateData, height) {
  258. var _a, _b;
  259. templateData.indentGuidesDisposable.dispose();
  260. (_b = (_a = this.renderer).disposeElement) === null || _b === void 0 ? void 0 : _b.call(_a, node, index, templateData.templateData, height);
  261. if (typeof height === 'number') {
  262. this.renderedNodes.delete(node);
  263. this.renderedElements.delete(node.element);
  264. }
  265. }
  266. disposeTemplate(templateData) {
  267. this.renderer.disposeTemplate(templateData.templateData);
  268. }
  269. onDidChangeTwistieState(element) {
  270. const node = this.renderedElements.get(element);
  271. if (!node) {
  272. return;
  273. }
  274. this.onDidChangeNodeTwistieState(node);
  275. }
  276. onDidChangeNodeTwistieState(node) {
  277. const data = this.renderedNodes.get(node);
  278. if (!data) {
  279. return;
  280. }
  281. this.renderTwistie(node, data.templateData);
  282. this._onDidChangeActiveNodes(this.activeNodes.elements);
  283. this.renderIndentGuides(node, data.templateData);
  284. }
  285. renderTwistie(node, templateData) {
  286. templateData.twistie.classList.remove(...Codicon.treeItemExpanded.classNamesArray);
  287. let twistieRendered = false;
  288. if (this.renderer.renderTwistie) {
  289. twistieRendered = this.renderer.renderTwistie(node.element, templateData.twistie);
  290. }
  291. if (node.collapsible && (!this.hideTwistiesOfChildlessElements || node.visibleChildrenCount > 0)) {
  292. if (!twistieRendered) {
  293. templateData.twistie.classList.add(...Codicon.treeItemExpanded.classNamesArray);
  294. }
  295. templateData.twistie.classList.add('collapsible');
  296. templateData.twistie.classList.toggle('collapsed', node.collapsed);
  297. }
  298. else {
  299. templateData.twistie.classList.remove('collapsible', 'collapsed');
  300. }
  301. if (node.collapsible) {
  302. templateData.container.setAttribute('aria-expanded', String(!node.collapsed));
  303. }
  304. else {
  305. templateData.container.removeAttribute('aria-expanded');
  306. }
  307. }
  308. renderIndentGuides(target, templateData) {
  309. clearNode(templateData.indent);
  310. templateData.indentGuidesDisposable.dispose();
  311. if (!this.shouldRenderIndentGuides) {
  312. return;
  313. }
  314. const disposableStore = new DisposableStore();
  315. const model = this.modelProvider();
  316. let node = target;
  317. while (true) {
  318. const ref = model.getNodeLocation(node);
  319. const parentRef = model.getParentNodeLocation(ref);
  320. if (!parentRef) {
  321. break;
  322. }
  323. const parent = model.getNode(parentRef);
  324. const guide = $('.indent-guide', { style: `width: ${this.indent}px` });
  325. if (this.activeIndentNodes.has(parent)) {
  326. guide.classList.add('active');
  327. }
  328. if (templateData.indent.childElementCount === 0) {
  329. templateData.indent.appendChild(guide);
  330. }
  331. else {
  332. templateData.indent.insertBefore(guide, templateData.indent.firstElementChild);
  333. }
  334. this.renderedIndentGuides.add(parent, guide);
  335. disposableStore.add(toDisposable(() => this.renderedIndentGuides.delete(parent, guide)));
  336. node = parent;
  337. }
  338. templateData.indentGuidesDisposable = disposableStore;
  339. }
  340. _onDidChangeActiveNodes(nodes) {
  341. if (!this.shouldRenderIndentGuides) {
  342. return;
  343. }
  344. const set = new Set();
  345. const model = this.modelProvider();
  346. nodes.forEach(node => {
  347. const ref = model.getNodeLocation(node);
  348. try {
  349. const parentRef = model.getParentNodeLocation(ref);
  350. if (node.collapsible && node.children.length > 0 && !node.collapsed) {
  351. set.add(node);
  352. }
  353. else if (parentRef) {
  354. set.add(model.getNode(parentRef));
  355. }
  356. }
  357. catch (_a) {
  358. // noop
  359. }
  360. });
  361. this.activeIndentNodes.forEach(node => {
  362. if (!set.has(node)) {
  363. this.renderedIndentGuides.forEach(node, line => line.classList.remove('active'));
  364. }
  365. });
  366. set.forEach(node => {
  367. if (!this.activeIndentNodes.has(node)) {
  368. this.renderedIndentGuides.forEach(node, line => line.classList.add('active'));
  369. }
  370. });
  371. this.activeIndentNodes = set;
  372. }
  373. dispose() {
  374. this.renderedNodes.clear();
  375. this.renderedElements.clear();
  376. this.indentGuidesDisposable.dispose();
  377. dispose(this.disposables);
  378. }
  379. }
  380. TreeRenderer.DefaultIndent = 8;
  381. class FindFilter {
  382. constructor(tree, keyboardNavigationLabelProvider, _filter) {
  383. this.tree = tree;
  384. this.keyboardNavigationLabelProvider = keyboardNavigationLabelProvider;
  385. this._filter = _filter;
  386. this._totalCount = 0;
  387. this._matchCount = 0;
  388. this._pattern = '';
  389. this._lowercasePattern = '';
  390. this.disposables = new DisposableStore();
  391. tree.onWillRefilter(this.reset, this, this.disposables);
  392. }
  393. get totalCount() { return this._totalCount; }
  394. get matchCount() { return this._matchCount; }
  395. filter(element, parentVisibility) {
  396. let visibility = 1 /* TreeVisibility.Visible */;
  397. if (this._filter) {
  398. const result = this._filter.filter(element, parentVisibility);
  399. if (typeof result === 'boolean') {
  400. visibility = result ? 1 /* TreeVisibility.Visible */ : 0 /* TreeVisibility.Hidden */;
  401. }
  402. else if (isFilterResult(result)) {
  403. visibility = getVisibleState(result.visibility);
  404. }
  405. else {
  406. visibility = result;
  407. }
  408. if (visibility === 0 /* TreeVisibility.Hidden */) {
  409. return false;
  410. }
  411. }
  412. this._totalCount++;
  413. if (!this._pattern) {
  414. this._matchCount++;
  415. return { data: FuzzyScore.Default, visibility };
  416. }
  417. const label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(element);
  418. const labels = Array.isArray(label) ? label : [label];
  419. for (const l of labels) {
  420. const labelStr = l && l.toString();
  421. if (typeof labelStr === 'undefined') {
  422. return { data: FuzzyScore.Default, visibility };
  423. }
  424. const score = fuzzyScore(this._pattern, this._lowercasePattern, 0, labelStr, labelStr.toLowerCase(), 0, { firstMatchCanBeWeak: true, boostFullMatch: true });
  425. if (score) {
  426. this._matchCount++;
  427. return labels.length === 1 ?
  428. { data: score, visibility } :
  429. { data: { label: labelStr, score: score }, visibility };
  430. }
  431. }
  432. if (this.tree.findMode === TreeFindMode.Filter) {
  433. return 2 /* TreeVisibility.Recurse */;
  434. }
  435. else {
  436. return { data: FuzzyScore.Default, visibility };
  437. }
  438. }
  439. reset() {
  440. this._totalCount = 0;
  441. this._matchCount = 0;
  442. }
  443. dispose() {
  444. dispose(this.disposables);
  445. }
  446. }
  447. export class ModeToggle extends Toggle {
  448. constructor(opts) {
  449. var _a;
  450. super({
  451. icon: Codicon.filter,
  452. title: localize('filter', "Filter"),
  453. isChecked: (_a = opts === null || opts === void 0 ? void 0 : opts.isChecked) !== null && _a !== void 0 ? _a : false,
  454. inputActiveOptionBorder: opts === null || opts === void 0 ? void 0 : opts.inputActiveOptionBorder,
  455. inputActiveOptionForeground: opts === null || opts === void 0 ? void 0 : opts.inputActiveOptionForeground,
  456. inputActiveOptionBackground: opts === null || opts === void 0 ? void 0 : opts.inputActiveOptionBackground
  457. });
  458. }
  459. }
  460. export var TreeFindMode;
  461. (function (TreeFindMode) {
  462. TreeFindMode[TreeFindMode["Highlight"] = 0] = "Highlight";
  463. TreeFindMode[TreeFindMode["Filter"] = 1] = "Filter";
  464. })(TreeFindMode || (TreeFindMode = {}));
  465. class FindWidget extends Disposable {
  466. constructor(container, tree, contextViewProvider, mode, options) {
  467. super();
  468. this.tree = tree;
  469. this.elements = h('.monaco-tree-type-filter', [
  470. h('.monaco-tree-type-filter-grab.codicon.codicon-debug-gripper@grab', { tabIndex: 0 }),
  471. h('.monaco-tree-type-filter-input@findInput'),
  472. h('.monaco-tree-type-filter-actionbar@actionbar'),
  473. ]);
  474. this.width = 0;
  475. this.right = 0;
  476. this._onDidDisable = new Emitter();
  477. container.appendChild(this.elements.root);
  478. this._register(toDisposable(() => container.removeChild(this.elements.root)));
  479. this.modeToggle = this._register(new ModeToggle(Object.assign(Object.assign({}, options), { isChecked: mode === TreeFindMode.Filter })));
  480. this.onDidChangeMode = Event.map(this.modeToggle.onChange, () => this.modeToggle.checked ? TreeFindMode.Filter : TreeFindMode.Highlight, this._store);
  481. this.findInput = this._register(new FindInput(this.elements.findInput, contextViewProvider, false, {
  482. label: localize('type to search', "Type to search"),
  483. additionalToggles: [this.modeToggle]
  484. }));
  485. this.actionbar = this._register(new ActionBar(this.elements.actionbar));
  486. this.mode = mode;
  487. const emitter = this._register(new DomEmitter(this.findInput.inputBox.inputElement, 'keydown'));
  488. const onKeyDown = this._register(Event.chain(emitter.event))
  489. .map(e => new StandardKeyboardEvent(e))
  490. .event;
  491. this._register(onKeyDown((e) => {
  492. switch (e.keyCode) {
  493. case 18 /* KeyCode.DownArrow */:
  494. e.preventDefault();
  495. e.stopPropagation();
  496. this.tree.domFocus();
  497. return;
  498. }
  499. }));
  500. const closeAction = this._register(new Action('close', localize('close', "Close"), 'codicon codicon-close', true, () => this.dispose()));
  501. this.actionbar.push(closeAction, { icon: true, label: false });
  502. const onGrabMouseDown = this._register(new DomEmitter(this.elements.grab, 'mousedown'));
  503. this._register(onGrabMouseDown.event(e => {
  504. const disposables = new DisposableStore();
  505. const onWindowMouseMove = disposables.add(new DomEmitter(window, 'mousemove'));
  506. const onWindowMouseUp = disposables.add(new DomEmitter(window, 'mouseup'));
  507. const startRight = this.right;
  508. const startX = e.pageX;
  509. this.elements.grab.classList.add('grabbing');
  510. const update = (e) => {
  511. const deltaX = e.pageX - startX;
  512. this.right = startRight - deltaX;
  513. this.layout();
  514. };
  515. disposables.add(onWindowMouseMove.event(update));
  516. disposables.add(onWindowMouseUp.event(e => {
  517. update(e);
  518. this.elements.grab.classList.remove('grabbing');
  519. disposables.dispose();
  520. }));
  521. }));
  522. const onGrabKeyDown = this._register(Event.chain(this._register(new DomEmitter(this.elements.grab, 'keydown')).event))
  523. .map(e => new StandardKeyboardEvent(e))
  524. .event;
  525. this._register(onGrabKeyDown((e) => {
  526. let right;
  527. if (e.keyCode === 15 /* KeyCode.LeftArrow */) {
  528. right = Number.POSITIVE_INFINITY;
  529. }
  530. else if (e.keyCode === 17 /* KeyCode.RightArrow */) {
  531. right = 0;
  532. }
  533. else if (e.keyCode === 10 /* KeyCode.Space */) {
  534. right = this.right === 0 ? Number.POSITIVE_INFINITY : 0;
  535. }
  536. if (right !== undefined) {
  537. e.preventDefault();
  538. e.stopPropagation();
  539. this.right = right;
  540. this.layout();
  541. }
  542. }));
  543. this.onDidChangeValue = this.findInput.onDidChange;
  544. this.style(options !== null && options !== void 0 ? options : {});
  545. }
  546. set mode(mode) {
  547. this.modeToggle.checked = mode === TreeFindMode.Filter;
  548. this.findInput.inputBox.setPlaceHolder(mode === TreeFindMode.Filter ? localize('type to filter', "Type to filter") : localize('type to search', "Type to search"));
  549. }
  550. style(styles) {
  551. this.findInput.style(styles);
  552. if (styles.listFilterWidgetBackground) {
  553. this.elements.root.style.backgroundColor = styles.listFilterWidgetBackground.toString();
  554. }
  555. if (styles.listFilterWidgetShadow) {
  556. this.elements.root.style.boxShadow = `0 0 8px 2px ${styles.listFilterWidgetShadow}`;
  557. }
  558. }
  559. layout(width = this.width) {
  560. this.width = width;
  561. this.right = clamp(this.right, 0, Math.max(0, width - 212));
  562. this.elements.root.style.right = `${this.right}px`;
  563. }
  564. showMessage(message) {
  565. this.findInput.showMessage(message);
  566. }
  567. clearMessage() {
  568. this.findInput.clearMessage();
  569. }
  570. dispose() {
  571. const _super = Object.create(null, {
  572. dispose: { get: () => super.dispose }
  573. });
  574. return __awaiter(this, void 0, void 0, function* () {
  575. this._onDidDisable.fire();
  576. this.elements.root.classList.add('disabled');
  577. yield timeout(300);
  578. _super.dispose.call(this);
  579. });
  580. }
  581. }
  582. class FindController {
  583. constructor(tree, model, view, filter, contextViewProvider) {
  584. var _a;
  585. this.tree = tree;
  586. this.view = view;
  587. this.filter = filter;
  588. this.contextViewProvider = contextViewProvider;
  589. this._pattern = '';
  590. this.width = 0;
  591. this._onDidChangeMode = new Emitter();
  592. this.onDidChangeMode = this._onDidChangeMode.event;
  593. this._onDidChangePattern = new Emitter();
  594. this._onDidChangeOpenState = new Emitter();
  595. this.onDidChangeOpenState = this._onDidChangeOpenState.event;
  596. this.enabledDisposables = new DisposableStore();
  597. this.disposables = new DisposableStore();
  598. this._mode = (_a = tree.options.defaultFindMode) !== null && _a !== void 0 ? _a : TreeFindMode.Highlight;
  599. model.onDidSplice(this.onDidSpliceModel, this, this.disposables);
  600. }
  601. get pattern() { return this._pattern; }
  602. get mode() { return this._mode; }
  603. set mode(mode) {
  604. if (mode === this._mode) {
  605. return;
  606. }
  607. this._mode = mode;
  608. if (this.widget) {
  609. this.widget.mode = this._mode;
  610. }
  611. this.tree.refilter();
  612. this.render();
  613. this._onDidChangeMode.fire(mode);
  614. }
  615. onDidSpliceModel() {
  616. if (!this.widget || this.pattern.length === 0) {
  617. return;
  618. }
  619. this.tree.refilter();
  620. this.render();
  621. }
  622. render() {
  623. var _a, _b;
  624. const noMatches = this.filter.totalCount > 0 && this.filter.matchCount === 0;
  625. if (this.pattern && noMatches) {
  626. (_a = this.widget) === null || _a === void 0 ? void 0 : _a.showMessage({ type: 2 /* MessageType.WARNING */, content: localize('not found', "No elements found.") });
  627. }
  628. else {
  629. (_b = this.widget) === null || _b === void 0 ? void 0 : _b.clearMessage();
  630. }
  631. }
  632. shouldAllowFocus(node) {
  633. if (!this.widget || !this.pattern || this._mode === TreeFindMode.Filter) {
  634. return true;
  635. }
  636. if (this.filter.totalCount > 0 && this.filter.matchCount <= 1) {
  637. return true;
  638. }
  639. return !FuzzyScore.isDefault(node.filterData);
  640. }
  641. style(styles) {
  642. var _a;
  643. this.styles = styles;
  644. (_a = this.widget) === null || _a === void 0 ? void 0 : _a.style(styles);
  645. }
  646. layout(width) {
  647. var _a;
  648. this.width = width;
  649. (_a = this.widget) === null || _a === void 0 ? void 0 : _a.layout(width);
  650. }
  651. dispose() {
  652. this._onDidChangePattern.dispose();
  653. this.enabledDisposables.dispose();
  654. this.disposables.dispose();
  655. }
  656. }
  657. function asTreeMouseEvent(event) {
  658. let target = TreeMouseEventTarget.Unknown;
  659. if (hasParentWithClass(event.browserEvent.target, 'monaco-tl-twistie', 'monaco-tl-row')) {
  660. target = TreeMouseEventTarget.Twistie;
  661. }
  662. else if (hasParentWithClass(event.browserEvent.target, 'monaco-tl-contents', 'monaco-tl-row')) {
  663. target = TreeMouseEventTarget.Element;
  664. }
  665. else if (hasParentWithClass(event.browserEvent.target, 'monaco-tree-type-filter', 'monaco-list')) {
  666. target = TreeMouseEventTarget.Filter;
  667. }
  668. return {
  669. browserEvent: event.browserEvent,
  670. element: event.element ? event.element.element : null,
  671. target
  672. };
  673. }
  674. function dfs(node, fn) {
  675. fn(node);
  676. node.children.forEach(child => dfs(child, fn));
  677. }
  678. /**
  679. * The trait concept needs to exist at the tree level, because collapsed
  680. * tree nodes will not be known by the list.
  681. */
  682. class Trait {
  683. constructor(getFirstViewElementWithTrait, identityProvider) {
  684. this.getFirstViewElementWithTrait = getFirstViewElementWithTrait;
  685. this.identityProvider = identityProvider;
  686. this.nodes = [];
  687. this._onDidChange = new Emitter();
  688. this.onDidChange = this._onDidChange.event;
  689. }
  690. get nodeSet() {
  691. if (!this._nodeSet) {
  692. this._nodeSet = this.createNodeSet();
  693. }
  694. return this._nodeSet;
  695. }
  696. set(nodes, browserEvent) {
  697. if (!(browserEvent === null || browserEvent === void 0 ? void 0 : browserEvent.__forceEvent) && equals(this.nodes, nodes)) {
  698. return;
  699. }
  700. this._set(nodes, false, browserEvent);
  701. }
  702. _set(nodes, silent, browserEvent) {
  703. this.nodes = [...nodes];
  704. this.elements = undefined;
  705. this._nodeSet = undefined;
  706. if (!silent) {
  707. const that = this;
  708. this._onDidChange.fire({ get elements() { return that.get(); }, browserEvent });
  709. }
  710. }
  711. get() {
  712. if (!this.elements) {
  713. this.elements = this.nodes.map(node => node.element);
  714. }
  715. return [...this.elements];
  716. }
  717. getNodes() {
  718. return this.nodes;
  719. }
  720. has(node) {
  721. return this.nodeSet.has(node);
  722. }
  723. onDidModelSplice({ insertedNodes, deletedNodes }) {
  724. if (!this.identityProvider) {
  725. const set = this.createNodeSet();
  726. const visit = (node) => set.delete(node);
  727. deletedNodes.forEach(node => dfs(node, visit));
  728. this.set([...set.values()]);
  729. return;
  730. }
  731. const deletedNodesIdSet = new Set();
  732. const deletedNodesVisitor = (node) => deletedNodesIdSet.add(this.identityProvider.getId(node.element).toString());
  733. deletedNodes.forEach(node => dfs(node, deletedNodesVisitor));
  734. const insertedNodesMap = new Map();
  735. const insertedNodesVisitor = (node) => insertedNodesMap.set(this.identityProvider.getId(node.element).toString(), node);
  736. insertedNodes.forEach(node => dfs(node, insertedNodesVisitor));
  737. const nodes = [];
  738. for (const node of this.nodes) {
  739. const id = this.identityProvider.getId(node.element).toString();
  740. const wasDeleted = deletedNodesIdSet.has(id);
  741. if (!wasDeleted) {
  742. nodes.push(node);
  743. }
  744. else {
  745. const insertedNode = insertedNodesMap.get(id);
  746. if (insertedNode) {
  747. nodes.push(insertedNode);
  748. }
  749. }
  750. }
  751. if (this.nodes.length > 0 && nodes.length === 0) {
  752. const node = this.getFirstViewElementWithTrait();
  753. if (node) {
  754. nodes.push(node);
  755. }
  756. }
  757. this._set(nodes, true);
  758. }
  759. createNodeSet() {
  760. const set = new Set();
  761. for (const node of this.nodes) {
  762. set.add(node);
  763. }
  764. return set;
  765. }
  766. }
  767. class TreeNodeListMouseController extends MouseController {
  768. constructor(list, tree) {
  769. super(list);
  770. this.tree = tree;
  771. }
  772. onViewPointer(e) {
  773. if (isButton(e.browserEvent.target) ||
  774. isInputElement(e.browserEvent.target) ||
  775. isMonacoEditor(e.browserEvent.target)) {
  776. return;
  777. }
  778. const node = e.element;
  779. if (!node) {
  780. return super.onViewPointer(e);
  781. }
  782. if (this.isSelectionRangeChangeEvent(e) || this.isSelectionSingleChangeEvent(e)) {
  783. return super.onViewPointer(e);
  784. }
  785. const target = e.browserEvent.target;
  786. const onTwistie = target.classList.contains('monaco-tl-twistie')
  787. || (target.classList.contains('monaco-icon-label') && target.classList.contains('folder-icon') && e.browserEvent.offsetX < 16);
  788. let expandOnlyOnTwistieClick = false;
  789. if (typeof this.tree.expandOnlyOnTwistieClick === 'function') {
  790. expandOnlyOnTwistieClick = this.tree.expandOnlyOnTwistieClick(node.element);
  791. }
  792. else {
  793. expandOnlyOnTwistieClick = !!this.tree.expandOnlyOnTwistieClick;
  794. }
  795. if (expandOnlyOnTwistieClick && !onTwistie && e.browserEvent.detail !== 2) {
  796. return super.onViewPointer(e);
  797. }
  798. if (!this.tree.expandOnDoubleClick && e.browserEvent.detail === 2) {
  799. return super.onViewPointer(e);
  800. }
  801. if (node.collapsible) {
  802. const model = this.tree.model; // internal
  803. const location = model.getNodeLocation(node);
  804. const recursive = e.browserEvent.altKey;
  805. this.tree.setFocus([location]);
  806. model.setCollapsed(location, undefined, recursive);
  807. if (expandOnlyOnTwistieClick && onTwistie) {
  808. return;
  809. }
  810. }
  811. super.onViewPointer(e);
  812. }
  813. onDoubleClick(e) {
  814. const onTwistie = e.browserEvent.target.classList.contains('monaco-tl-twistie');
  815. if (onTwistie || !this.tree.expandOnDoubleClick) {
  816. return;
  817. }
  818. super.onDoubleClick(e);
  819. }
  820. }
  821. /**
  822. * We use this List subclass to restore selection and focus as nodes
  823. * get rendered in the list, possibly due to a node expand() call.
  824. */
  825. class TreeNodeList extends List {
  826. constructor(user, container, virtualDelegate, renderers, focusTrait, selectionTrait, anchorTrait, options) {
  827. super(user, container, virtualDelegate, renderers, options);
  828. this.focusTrait = focusTrait;
  829. this.selectionTrait = selectionTrait;
  830. this.anchorTrait = anchorTrait;
  831. }
  832. createMouseController(options) {
  833. return new TreeNodeListMouseController(this, options.tree);
  834. }
  835. splice(start, deleteCount, elements = []) {
  836. super.splice(start, deleteCount, elements);
  837. if (elements.length === 0) {
  838. return;
  839. }
  840. const additionalFocus = [];
  841. const additionalSelection = [];
  842. let anchor;
  843. elements.forEach((node, index) => {
  844. if (this.focusTrait.has(node)) {
  845. additionalFocus.push(start + index);
  846. }
  847. if (this.selectionTrait.has(node)) {
  848. additionalSelection.push(start + index);
  849. }
  850. if (this.anchorTrait.has(node)) {
  851. anchor = start + index;
  852. }
  853. });
  854. if (additionalFocus.length > 0) {
  855. super.setFocus(distinct([...super.getFocus(), ...additionalFocus]));
  856. }
  857. if (additionalSelection.length > 0) {
  858. super.setSelection(distinct([...super.getSelection(), ...additionalSelection]));
  859. }
  860. if (typeof anchor === 'number') {
  861. super.setAnchor(anchor);
  862. }
  863. }
  864. setFocus(indexes, browserEvent, fromAPI = false) {
  865. super.setFocus(indexes, browserEvent);
  866. if (!fromAPI) {
  867. this.focusTrait.set(indexes.map(i => this.element(i)), browserEvent);
  868. }
  869. }
  870. setSelection(indexes, browserEvent, fromAPI = false) {
  871. super.setSelection(indexes, browserEvent);
  872. if (!fromAPI) {
  873. this.selectionTrait.set(indexes.map(i => this.element(i)), browserEvent);
  874. }
  875. }
  876. setAnchor(index, fromAPI = false) {
  877. super.setAnchor(index);
  878. if (!fromAPI) {
  879. if (typeof index === 'undefined') {
  880. this.anchorTrait.set([]);
  881. }
  882. else {
  883. this.anchorTrait.set([this.element(index)]);
  884. }
  885. }
  886. }
  887. }
  888. export class AbstractTree {
  889. constructor(_user, container, delegate, renderers, _options = {}) {
  890. var _a;
  891. this._user = _user;
  892. this._options = _options;
  893. this.eventBufferer = new EventBufferer();
  894. this.onDidChangeFindOpenState = Event.None;
  895. this.disposables = new DisposableStore();
  896. this._onWillRefilter = new Emitter();
  897. this.onWillRefilter = this._onWillRefilter.event;
  898. this._onDidUpdateOptions = new Emitter();
  899. const treeDelegate = new ComposedTreeDelegate(delegate);
  900. const onDidChangeCollapseStateRelay = new Relay();
  901. const onDidChangeActiveNodes = new Relay();
  902. const activeNodes = this.disposables.add(new EventCollection(onDidChangeActiveNodes.event));
  903. this.renderers = renderers.map(r => new TreeRenderer(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options));
  904. for (const r of this.renderers) {
  905. this.disposables.add(r);
  906. }
  907. let filter;
  908. if (_options.keyboardNavigationLabelProvider) {
  909. filter = new FindFilter(this, _options.keyboardNavigationLabelProvider, _options.filter);
  910. _options = Object.assign(Object.assign({}, _options), { filter: filter }); // TODO need typescript help here
  911. this.disposables.add(filter);
  912. }
  913. this.focus = new Trait(() => this.view.getFocusedElements()[0], _options.identityProvider);
  914. this.selection = new Trait(() => this.view.getSelectedElements()[0], _options.identityProvider);
  915. this.anchor = new Trait(() => this.view.getAnchorElement(), _options.identityProvider);
  916. this.view = new TreeNodeList(_user, container, treeDelegate, this.renderers, this.focus, this.selection, this.anchor, Object.assign(Object.assign({}, asListOptions(() => this.model, _options)), { tree: this }));
  917. this.model = this.createModel(_user, this.view, _options);
  918. onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
  919. const onDidModelSplice = Event.forEach(this.model.onDidSplice, e => {
  920. this.eventBufferer.bufferEvents(() => {
  921. this.focus.onDidModelSplice(e);
  922. this.selection.onDidModelSplice(e);
  923. });
  924. }, this.disposables);
  925. // Make sure the `forEach` always runs
  926. onDidModelSplice(() => null, null, this.disposables);
  927. // Active nodes can change when the model changes or when focus or selection change.
  928. // We debounce it with 0 delay since these events may fire in the same stack and we only
  929. // want to run this once. It also doesn't matter if it runs on the next tick since it's only
  930. // a nice to have UI feature.
  931. onDidChangeActiveNodes.input = Event.chain(Event.any(onDidModelSplice, this.focus.onDidChange, this.selection.onDidChange))
  932. .debounce(() => null, 0)
  933. .map(() => {
  934. const set = new Set();
  935. for (const node of this.focus.getNodes()) {
  936. set.add(node);
  937. }
  938. for (const node of this.selection.getNodes()) {
  939. set.add(node);
  940. }
  941. return [...set.values()];
  942. }).event;
  943. if (_options.keyboardSupport !== false) {
  944. const onKeyDown = Event.chain(this.view.onKeyDown)
  945. .filter(e => !isInputElement(e.target))
  946. .map(e => new StandardKeyboardEvent(e));
  947. onKeyDown.filter(e => e.keyCode === 15 /* KeyCode.LeftArrow */).on(this.onLeftArrow, this, this.disposables);
  948. onKeyDown.filter(e => e.keyCode === 17 /* KeyCode.RightArrow */).on(this.onRightArrow, this, this.disposables);
  949. onKeyDown.filter(e => e.keyCode === 10 /* KeyCode.Space */).on(this.onSpace, this, this.disposables);
  950. }
  951. if (((_a = _options.findWidgetEnabled) !== null && _a !== void 0 ? _a : true) && _options.keyboardNavigationLabelProvider && _options.contextViewProvider) {
  952. this.findController = new FindController(this, this.model, this.view, filter, _options.contextViewProvider);
  953. this.focusNavigationFilter = node => this.findController.shouldAllowFocus(node);
  954. this.onDidChangeFindOpenState = this.findController.onDidChangeOpenState;
  955. this.disposables.add(this.findController);
  956. this.onDidChangeFindMode = this.findController.onDidChangeMode;
  957. }
  958. else {
  959. this.onDidChangeFindMode = Event.None;
  960. }
  961. this.styleElement = createStyleSheet(this.view.getHTMLElement());
  962. this.getHTMLElement().classList.toggle('always', this._options.renderIndentGuides === RenderIndentGuides.Always);
  963. }
  964. get onDidChangeFocus() { return this.eventBufferer.wrapEvent(this.focus.onDidChange); }
  965. get onDidChangeSelection() { return this.eventBufferer.wrapEvent(this.selection.onDidChange); }
  966. get onMouseDblClick() { return Event.filter(Event.map(this.view.onMouseDblClick, asTreeMouseEvent), e => e.target !== TreeMouseEventTarget.Filter); }
  967. get onPointer() { return Event.map(this.view.onPointer, asTreeMouseEvent); }
  968. get onDidFocus() { return this.view.onDidFocus; }
  969. get onDidChangeModel() { return Event.signal(this.model.onDidSplice); }
  970. get onDidChangeCollapseState() { return this.model.onDidChangeCollapseState; }
  971. get findMode() { var _a, _b; return (_b = (_a = this.findController) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : TreeFindMode.Highlight; }
  972. set findMode(findMode) { if (this.findController) {
  973. this.findController.mode = findMode;
  974. } }
  975. get expandOnDoubleClick() { return typeof this._options.expandOnDoubleClick === 'undefined' ? true : this._options.expandOnDoubleClick; }
  976. get expandOnlyOnTwistieClick() { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? true : this._options.expandOnlyOnTwistieClick; }
  977. get onDidDispose() { return this.view.onDidDispose; }
  978. updateOptions(optionsUpdate = {}) {
  979. this._options = Object.assign(Object.assign({}, this._options), optionsUpdate);
  980. for (const renderer of this.renderers) {
  981. renderer.updateOptions(optionsUpdate);
  982. }
  983. this.view.updateOptions(this._options);
  984. this._onDidUpdateOptions.fire(this._options);
  985. this.getHTMLElement().classList.toggle('always', this._options.renderIndentGuides === RenderIndentGuides.Always);
  986. }
  987. get options() {
  988. return this._options;
  989. }
  990. // Widget
  991. getHTMLElement() {
  992. return this.view.getHTMLElement();
  993. }
  994. get scrollTop() {
  995. return this.view.scrollTop;
  996. }
  997. set scrollTop(scrollTop) {
  998. this.view.scrollTop = scrollTop;
  999. }
  1000. domFocus() {
  1001. this.view.domFocus();
  1002. }
  1003. layout(height, width) {
  1004. var _a;
  1005. this.view.layout(height, width);
  1006. if (isNumber(width)) {
  1007. (_a = this.findController) === null || _a === void 0 ? void 0 : _a.layout(width);
  1008. }
  1009. }
  1010. style(styles) {
  1011. var _a;
  1012. const suffix = `.${this.view.domId}`;
  1013. const content = [];
  1014. if (styles.treeIndentGuidesStroke) {
  1015. content.push(`.monaco-list${suffix}:hover .monaco-tl-indent > .indent-guide, .monaco-list${suffix}.always .monaco-tl-indent > .indent-guide { border-color: ${styles.treeIndentGuidesStroke.transparent(0.4)}; }`);
  1016. content.push(`.monaco-list${suffix} .monaco-tl-indent > .indent-guide.active { border-color: ${styles.treeIndentGuidesStroke}; }`);
  1017. }
  1018. this.styleElement.textContent = content.join('\n');
  1019. (_a = this.findController) === null || _a === void 0 ? void 0 : _a.style(styles);
  1020. this.view.style(styles);
  1021. }
  1022. // Tree navigation
  1023. getParentElement(location) {
  1024. const parentRef = this.model.getParentNodeLocation(location);
  1025. const parentNode = this.model.getNode(parentRef);
  1026. return parentNode.element;
  1027. }
  1028. getFirstElementChild(location) {
  1029. return this.model.getFirstElementChild(location);
  1030. }
  1031. // Tree
  1032. getNode(location) {
  1033. return this.model.getNode(location);
  1034. }
  1035. collapse(location, recursive = false) {
  1036. return this.model.setCollapsed(location, true, recursive);
  1037. }
  1038. expand(location, recursive = false) {
  1039. return this.model.setCollapsed(location, false, recursive);
  1040. }
  1041. isCollapsible(location) {
  1042. return this.model.isCollapsible(location);
  1043. }
  1044. setCollapsible(location, collapsible) {
  1045. return this.model.setCollapsible(location, collapsible);
  1046. }
  1047. isCollapsed(location) {
  1048. return this.model.isCollapsed(location);
  1049. }
  1050. refilter() {
  1051. this._onWillRefilter.fire(undefined);
  1052. this.model.refilter();
  1053. }
  1054. setSelection(elements, browserEvent) {
  1055. const nodes = elements.map(e => this.model.getNode(e));
  1056. this.selection.set(nodes, browserEvent);
  1057. const indexes = elements.map(e => this.model.getListIndex(e)).filter(i => i > -1);
  1058. this.view.setSelection(indexes, browserEvent, true);
  1059. }
  1060. getSelection() {
  1061. return this.selection.get();
  1062. }
  1063. setFocus(elements, browserEvent) {
  1064. const nodes = elements.map(e => this.model.getNode(e));
  1065. this.focus.set(nodes, browserEvent);
  1066. const indexes = elements.map(e => this.model.getListIndex(e)).filter(i => i > -1);
  1067. this.view.setFocus(indexes, browserEvent, true);
  1068. }
  1069. getFocus() {
  1070. return this.focus.get();
  1071. }
  1072. reveal(location, relativeTop) {
  1073. this.model.expandTo(location);
  1074. const index = this.model.getListIndex(location);
  1075. if (index === -1) {
  1076. return;
  1077. }
  1078. this.view.reveal(index, relativeTop);
  1079. }
  1080. // List
  1081. onLeftArrow(e) {
  1082. e.preventDefault();
  1083. e.stopPropagation();
  1084. const nodes = this.view.getFocusedElements();
  1085. if (nodes.length === 0) {
  1086. return;
  1087. }
  1088. const node = nodes[0];
  1089. const location = this.model.getNodeLocation(node);
  1090. const didChange = this.model.setCollapsed(location, true);
  1091. if (!didChange) {
  1092. const parentLocation = this.model.getParentNodeLocation(location);
  1093. if (!parentLocation) {
  1094. return;
  1095. }
  1096. const parentListIndex = this.model.getListIndex(parentLocation);
  1097. this.view.reveal(parentListIndex);
  1098. this.view.setFocus([parentListIndex]);
  1099. }
  1100. }
  1101. onRightArrow(e) {
  1102. e.preventDefault();
  1103. e.stopPropagation();
  1104. const nodes = this.view.getFocusedElements();
  1105. if (nodes.length === 0) {
  1106. return;
  1107. }
  1108. const node = nodes[0];
  1109. const location = this.model.getNodeLocation(node);
  1110. const didChange = this.model.setCollapsed(location, false);
  1111. if (!didChange) {
  1112. if (!node.children.some(child => child.visible)) {
  1113. return;
  1114. }
  1115. const [focusedIndex] = this.view.getFocus();
  1116. const firstChildIndex = focusedIndex + 1;
  1117. this.view.reveal(firstChildIndex);
  1118. this.view.setFocus([firstChildIndex]);
  1119. }
  1120. }
  1121. onSpace(e) {
  1122. e.preventDefault();
  1123. e.stopPropagation();
  1124. const nodes = this.view.getFocusedElements();
  1125. if (nodes.length === 0) {
  1126. return;
  1127. }
  1128. const node = nodes[0];
  1129. const location = this.model.getNodeLocation(node);
  1130. const recursive = e.browserEvent.altKey;
  1131. this.model.setCollapsed(location, undefined, recursive);
  1132. }
  1133. dispose() {
  1134. dispose(this.disposables);
  1135. this.view.dispose();
  1136. }
  1137. }