Skip to content

Commit

Permalink
Implement Save without Formatting command
Browse files Browse the repository at this point in the history
+ Adds key binding of `ctrlcmd+k s` to save without formatting
+ Implements the command

Signed-off-by: Duc Nguyen <[email protected]>
  • Loading branch information
DucNgn authored and vince-fugnitto committed Sep 28, 2020
1 parent 025d633 commit 0e79595
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 16 deletions.
15 changes: 15 additions & 0 deletions packages/core/src/browser/common-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,11 @@ export namespace CommonCommands {
category: FILE_CATEGORY,
label: 'Save',
};
export const SAVE_WITHOUT_FORMATTING: Command = {
id: 'core.saveWithoutFormatting',
category: FILE_CATEGORY,
label: 'Save without Formatting',
};
export const SAVE_ALL: Command = {
id: 'core.saveAll',
category: FILE_CATEGORY,
Expand Down Expand Up @@ -445,6 +450,9 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
registry.registerMenuAction(CommonMenus.FILE_SAVE, {
commandId: CommonCommands.SAVE.id
});
registry.registerMenuAction(CommonMenus.FILE_SAVE, {
commandId: CommonCommands.SAVE_WITHOUT_FORMATTING.id
});
registry.registerMenuAction(CommonMenus.FILE_SAVE, {
commandId: CommonCommands.SAVE_ALL.id
});
Expand Down Expand Up @@ -747,6 +755,9 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
commandRegistry.registerCommand(CommonCommands.SAVE, {
execute: () => this.shell.save()
});
commandRegistry.registerCommand(CommonCommands.SAVE_WITHOUT_FORMATTING, {
execute: () => this.shell.save({ skipFormatting: true })
});
commandRegistry.registerCommand(CommonCommands.SAVE_ALL, {
execute: () => this.shell.saveAll()
});
Expand Down Expand Up @@ -924,6 +935,10 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
command: CommonCommands.SAVE.id,
keybinding: 'ctrlcmd+s'
},
{
command: CommonCommands.SAVE_WITHOUT_FORMATTING.id,
keybinding: 'ctrlcmd+k s'
},
{
command: CommonCommands.SAVE_ALL.id,
keybinding: 'ctrlcmd+alt+s'
Expand Down
13 changes: 10 additions & 3 deletions packages/core/src/browser/saveable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface Saveable {
/**
* Saves dirty changes.
*/
save(): MaybePromise<void>;
save(options?: SaveOptions): MaybePromise<void>;
/**
* Reverts dirty changes.
*/
Expand Down Expand Up @@ -87,10 +87,10 @@ export namespace Saveable {
return !!getDirty(arg);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function save(arg: any): Promise<void> {
export async function save(arg: any, options?: SaveOptions): Promise<void> {
const saveable = get(arg);
if (saveable) {
await saveable.save();
await saveable.save(options);
}
}
export function apply(widget: Widget): SaveableWidget | undefined {
Expand Down Expand Up @@ -179,6 +179,13 @@ export namespace SaveableWidget {
}
}

export interface SaveOptions {
/**
* Controls whether formatting should be applied upon saving
*/
readonly skipFormatting?: boolean;
}

/**
* The class name added to the dirty widget's title.
*/
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/browser/shell/application-shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { Message } from '@phosphor/messaging';
import { IDragEvent } from '@phosphor/dragdrop';
import { RecursivePartial, Event as CommonEvent, DisposableCollection, Disposable } from '../../common';
import { animationFrame } from '../browser';
import { Saveable, SaveableWidget } from '../saveable';
import { Saveable, SaveableWidget, SaveOptions } from '../saveable';
import { StatusBarImpl, StatusBarEntry, StatusBarAlignment } from '../status-bar/status-bar';
import { TheiaDockPanel, BOTTOM_AREA_ID, MAIN_AREA_ID } from './theia-dock-panel';
import { SidePanelHandler, SidePanel, SidePanelHandlerFactory } from './side-panel-handler';
Expand Down Expand Up @@ -1731,8 +1731,8 @@ export class ApplicationShell extends Widget {
/**
* Save the current widget if it is dirty.
*/
async save(): Promise<void> {
await Saveable.save(this.currentWidget);
async save(options?: SaveOptions): Promise<void> {
await Saveable.save(this.currentWidget, options);
}

/**
Expand All @@ -1746,7 +1746,7 @@ export class ApplicationShell extends Widget {
* Save all dirty widgets.
*/
async saveAll(): Promise<void> {
await Promise.all(this.tracker.widgets.map(Saveable.save));
await Promise.all(this.tracker.widgets.map(widget => Saveable.save(widget)));
}

/**
Expand Down
19 changes: 10 additions & 9 deletions packages/monaco/src/browser/monaco-editor-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { Emitter, Event } from '@theia/core/lib/common/event';
import { CancellationTokenSource, CancellationToken } from '@theia/core/lib/common/cancellation';
import { Resource, ResourceError, ResourceVersion } from '@theia/core/lib/common/resource';
import { Range } from 'vscode-languageserver-types';
import { Saveable } from '@theia/core/lib/browser/saveable';
import { Saveable, SaveOptions } from '@theia/core/lib/browser/saveable';
import { MonacoToProtocolConverter } from './monaco-to-protocol-converter';
import { ProtocolToMonacoConverter } from './protocol-to-monaco-converter';
import { ILogger, Loggable, Log } from '@theia/core/lib/common/logger';
Expand All @@ -36,6 +36,7 @@ type ITextEditorModel = monaco.editor.ITextEditorModel;
export interface WillSaveMonacoModelEvent {
readonly model: MonacoEditorModel;
readonly reason: TextDocumentSaveReason;
readonly options?: SaveOptions;
waitUntil(thenable: Thenable<monaco.editor.IIdentifiedSingleEditOperation[]>): void;
}

Expand Down Expand Up @@ -283,8 +284,8 @@ export class MonacoEditorModel implements ITextEditorModel, TextEditorDocument {
return this;
}

save(): Promise<void> {
return this.scheduleSave(TextDocumentSaveReason.Manual);
save(options?: SaveOptions): Promise<void> {
return this.scheduleSave(TextDocumentSaveReason.Manual, undefined, undefined, options);
}

protected pendingOperation = Promise.resolve();
Expand Down Expand Up @@ -397,8 +398,8 @@ export class MonacoEditorModel implements ITextEditorModel, TextEditorDocument {
return this.saveCancellationTokenSource.token;
}

protected scheduleSave(reason: TextDocumentSaveReason, token: CancellationToken = this.cancelSave(), overwriteEncoding?: boolean): Promise<void> {
return this.run(() => this.doSave(reason, token, overwriteEncoding));
protected scheduleSave(reason: TextDocumentSaveReason, token: CancellationToken = this.cancelSave(), overwriteEncoding?: boolean, options?: SaveOptions): Promise<void> {
return this.run(() => this.doSave(reason, token, overwriteEncoding, options));
}

protected ignoreContentChanges = false;
Expand Down Expand Up @@ -457,12 +458,12 @@ export class MonacoEditorModel implements ITextEditorModel, TextEditorDocument {
}
}

protected async doSave(reason: TextDocumentSaveReason, token: CancellationToken, overwriteEncoding?: boolean): Promise<void> {
protected async doSave(reason: TextDocumentSaveReason, token: CancellationToken, overwriteEncoding?: boolean, options?: SaveOptions): Promise<void> {
if (token.isCancellationRequested || !this.resource.saveContents) {
return;
}

await this.fireWillSaveModel(reason, token);
await this.fireWillSaveModel(reason, token, options);
if (token.isCancellationRequested) {
return;
}
Expand Down Expand Up @@ -496,7 +497,7 @@ export class MonacoEditorModel implements ITextEditorModel, TextEditorDocument {
}
}

protected async fireWillSaveModel(reason: TextDocumentSaveReason, token: CancellationToken): Promise<void> {
protected async fireWillSaveModel(reason: TextDocumentSaveReason, token: CancellationToken, options?: SaveOptions): Promise<void> {
type EditContributor = Thenable<monaco.editor.IIdentifiedSingleEditOperation[]>;

const firing = this.onWillSaveModelEmitter.sequence(async listener => {
Expand All @@ -507,7 +508,7 @@ export class MonacoEditorModel implements ITextEditorModel, TextEditorDocument {
const { version } = this;

const event = {
model: this, reason,
model: this, reason, options,
waitUntil: (thenable: EditContributor) => {
if (Object.isFrozen(waitables)) {
throw new Error('waitUntil cannot be called asynchronously.');
Expand Down
3 changes: 3 additions & 0 deletions packages/monaco/src/browser/monaco-editor-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ export class MonacoEditorProvider {
if (event.reason !== TextDocumentSaveReason.Manual) {
return [];
}
if (event.options?.skipFormatting) {
return [];
}
const overrideIdentifier = editor.document.languageId;
const uri = editor.uri.toString();
const formatOnSave = this.editorPreferences.get({ preferenceName: 'editor.formatOnSave', overrideIdentifier }, undefined, uri)!;
Expand Down

0 comments on commit 0e79595

Please sign in to comment.