ATL-1063: Integrated search in workspace into IDE

- Reordered the sidebar views.
 - Increased the default sidebar width.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
Akos Kitta 2021-03-11 14:40:48 +01:00 committed by Akos Kitta
parent eadc993854
commit 5a262d42c1
9 changed files with 137 additions and 8 deletions

View File

@ -35,7 +35,9 @@ import {
CommonFrontendContribution as TheiaCommonFrontendContribution,
KeybindingRegistry as TheiaKeybindingRegistry,
TabBarRendererFactory,
ContextMenuRenderer
ContextMenuRenderer,
createTreeContainer,
TreeWidget
} from '@theia/core/lib/browser';
import { MenuContribution } from '@theia/core/lib/common/menu';
import { ApplicationShell } from './theia/core/application-shell';
@ -147,6 +149,10 @@ import { WorkspaceVariableContribution as TheiaWorkspaceVariableContribution } f
import { WorkspaceVariableContribution } from './theia/workspace/workspace-variable-contribution';
import { DebugConfigurationManager } from './theia/debug/debug-configuration-manager';
import { DebugConfigurationManager as TheiaDebugConfigurationManager } from '@theia/debug/lib/browser/debug-configuration-manager';
import { SearchInWorkspaceWidget as TheiaSearchInWorkspaceWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-widget';
import { SearchInWorkspaceWidget } from './theia/search-in-workspace/search-in-workspace-widget';
import { SearchInWorkspaceResultTreeWidget as TheiaSearchInWorkspaceResultTreeWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-result-tree-widget';
import { SearchInWorkspaceResultTreeWidget } from './theia/search-in-workspace/search-in-workspace-result-tree-widget';
const ElementQueries = require('css-element-queries/src/ElementQueries');
@ -300,6 +306,15 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(MonacoTextModelService).toSelf().inSingletonScope();
rebind(TheiaMonacoTextModelService).toService(MonacoTextModelService);
bind(SearchInWorkspaceWidget).toSelf();
rebind(TheiaSearchInWorkspaceWidget).toService(SearchInWorkspaceWidget);
rebind(TheiaSearchInWorkspaceResultTreeWidget).toDynamicValue(({ container }) => {
const childContainer = createTreeContainer(container);
childContainer.bind(SearchInWorkspaceResultTreeWidget).toSelf()
childContainer.rebind(TreeWidget).toService(SearchInWorkspaceResultTreeWidget);
return childContainer.get(SearchInWorkspaceResultTreeWidget);
});
// Show a disconnected status bar, when the daemon is not available
bind(ApplicationConnectionStatusContribution).toSelf().inSingletonScope();
rebind(TheiaApplicationConnectionStatusContribution).toService(ApplicationConnectionStatusContribution);

View File

@ -12,7 +12,7 @@ export class BoardsListWidgetFrontendContribution extends ListWidgetFrontendCont
widgetName: BoardsListWidget.WIDGET_LABEL,
defaultWidgetOptions: {
area: 'left',
rank: 600
rank: 2
},
toggleCommandId: `${BoardsListWidget.WIDGET_ID}:toggle`,
toggleKeybinding: 'CtrlCmd+Shift+B'

View File

@ -14,7 +14,7 @@ export class LibraryListWidgetFrontendContribution extends AbstractViewContribut
widgetName: LibraryListWidget.WIDGET_LABEL,
defaultWidgetOptions: {
area: 'left',
rank: 700
rank: 3
},
toggleCommandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
toggleKeybinding: 'CtrlCmd+Shift+I'

View File

@ -37,8 +37,13 @@
background-color: var(--theia-warningBackground);
}
/* Overrule the default Theia CSS button styles. */
/* Makes the sidepanel a bit wider when opening the widget */
.p-DockPanel-widget {
min-width: 200px;
min-height: 200px;
}
/* Overrule the default Theia CSS button styles. */
button.theia-button,
.theia-button {
border: 1px solid var(--theia-dropdown-border);

View File

@ -6,6 +6,11 @@ import { unregisterSubmenu } from '../../menu/arduino-menus';
@injectable()
export class DebugFrontendApplicationContribution extends TheiaDebugFrontendApplicationContribution {
constructor() {
super()
this.options.defaultWidgetOptions.rank = 4;
}
registerMenus(registry: MenuModelRegistry): void {
super.registerMenus(registry);
unregisterSubmenu(DebugMenus.DEBUG, registry);

View File

@ -1,12 +1,28 @@
import { injectable } from 'inversify';
import { inject, injectable } from 'inversify';
import { WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands';
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
import { FileNavigatorContribution as TheiaFileNavigatorContribution } from '@theia/navigator/lib/browser/navigator-contribution';
import { FileNavigatorPreferences } from '@theia/navigator/lib/browser/navigator-preferences';
import { OpenerService } from '@theia/core/lib/browser/opener-service';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
import { FileNavigatorFilter } from '@theia/navigator/lib/browser/navigator-filter';
import { WorkspacePreferences } from '@theia/workspace/lib/browser/workspace-preferences';
@injectable()
export class FileNavigatorContribution extends TheiaFileNavigatorContribution {
constructor(
@inject(FileNavigatorPreferences) protected readonly fileNavigatorPreferences: FileNavigatorPreferences,
@inject(OpenerService) protected readonly openerService: OpenerService,
@inject(FileNavigatorFilter) protected readonly fileNavigatorFilter: FileNavigatorFilter,
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService,
@inject(WorkspacePreferences) protected readonly workspacePreferences: WorkspacePreferences
) {
super(fileNavigatorPreferences, openerService, fileNavigatorFilter, workspaceService, workspacePreferences);
this.options.defaultWidgetOptions.rank = 1;
}
async initializeLayout(app: FrontendApplication): Promise<void> {
// NOOP
}

View File

@ -1,14 +1,14 @@
import { injectable } from 'inversify';
import { MenuModelRegistry } from '@theia/core/lib/common/menu';
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
import { SearchInWorkspaceFrontendContribution as TheiaSearchInWorkspaceFrontendContribution, SearchInWorkspaceCommands } from '@theia/search-in-workspace/lib/browser/search-in-workspace-frontend-contribution';
@injectable()
export class SearchInWorkspaceFrontendContribution extends TheiaSearchInWorkspaceFrontendContribution {
async initializeLayout(app: FrontendApplication): Promise<void> {
// NOOP
constructor() {
super();
this.options.defaultWidgetOptions.rank = 5;
}
registerMenus(registry: MenuModelRegistry): void {

View File

@ -0,0 +1,34 @@
import { injectable } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { MEMORY_TEXT } from '@theia/search-in-workspace/lib/browser/in-memory-text-resource';
import { SearchInWorkspaceFileNode, SearchInWorkspaceResultTreeWidget as TheiaSearchInWorkspaceResultTreeWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-result-tree-widget';
/**
* Workaround for https://github.com/eclipse-theia/theia/pull/9192/.
*/
@injectable()
export class SearchInWorkspaceResultTreeWidget extends TheiaSearchInWorkspaceResultTreeWidget {
protected async createReplacePreview(node: SearchInWorkspaceFileNode): Promise<URI> {
const fileUri = new URI(node.fileUri).withScheme('file');
const openedEditor = this.editorManager.all.find(({ editor }) => editor.uri.toString() === fileUri.toString());
let content: string;
if (openedEditor) {
content = openedEditor.editor.document.getText();
} else {
const resource = await this.fileResourceResolver.resolve(fileUri);
content = await resource.readContents();
}
const lines = content.split('\n');
node.children.map(l => {
const leftPositionedNodes = node.children.filter(rl => rl.line === l.line && rl.character < l.character);
const diff = (this._replaceTerm.length - this.searchTerm.length) * leftPositionedNodes.length;
const start = lines[l.line - 1].substr(0, l.character - 1 + diff);
const end = lines[l.line - 1].substr(l.character - 1 + diff + l.length);
lines[l.line - 1] = start + this._replaceTerm + end;
});
return fileUri.withScheme(MEMORY_TEXT).withQuery(lines.join('\n'));
}
}

View File

@ -0,0 +1,54 @@
import { injectable } from 'inversify';
import * as React from 'react';
import { Key, KeyCode } from '@theia/core/lib/browser';
import { SearchInWorkspaceWidget as TheiaSearchInWorkspaceWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-widget';
/**
* Workaround for https://github.com/eclipse-theia/theia/pull/9183.
*/
@injectable()
export class SearchInWorkspaceWidget extends TheiaSearchInWorkspaceWidget {
protected renderGlobField(kind: 'include' | 'exclude'): React.ReactNode {
const currentValue = this.searchInWorkspaceOptions[kind];
const value = currentValue && currentValue.join(', ') || '';
return <div className='glob-field'>
<div className='label'>{'files to ' + kind}</div>
<input
className='theia-input'
type='text'
size={1}
defaultValue={value}
id={kind + '-glob-field'}
onKeyUp={e => {
if (e.target) {
const targetValue = (e.target as HTMLInputElement).value || '';
let shouldSearch = Key.ENTER.keyCode === KeyCode.createKeyCode(e.nativeEvent).key?.keyCode;
const currentOptions = (this.searchInWorkspaceOptions[kind] || []).slice().map(s => s.trim()).sort();
const candidateOptions = this.splitOnComma(targetValue).map(s => s.trim()).sort();
const sameAs = (left: string[], right: string[]) => {
if (left.length !== right.length) {
return false;
}
for (let i = 0; i < left.length; i++) {
if (left[i] !== right[i]) {
return false;
}
}
return true;
};
if (!sameAs(currentOptions, candidateOptions)) {
this.searchInWorkspaceOptions[kind] = this.splitOnComma(targetValue);
shouldSearch = true;
}
if (shouldSearch) {
this.resultTreeWidget.search(this.searchTerm, this.searchInWorkspaceOptions);
}
}
}}
onFocus={kind === 'include' ? this.handleFocusIncludesInputBox : this.handleFocusExcludesInputBox}
onBlur={kind === 'include' ? this.handleBlurIncludesInputBox : this.handleBlurExcludesInputBox}></input>
</div>;
}
}