mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-10-11 04:18:33 +00:00

Arduino IDE's "Edit > Copy for Forum (Markdown)" feature copies the contents of the currently selected editor tab to the clipboard, with "fenced code block" markup added to provide correct formatting when the content is posted to a platform supporting Markdown language such as Arduino Forum, GitHub, Stack Exchange, etc. One of the most common points of friction between the volunteer helpers on the forum and the newcomers requesting assistance is the failure to use the correct markup when posting code. In the best case scenario the code and thread is made less readable and less convenient to copy to the IDE for further investigation. Components of the code often resemble markup, which causes it to be corrupted by the forum's renderer. Even in cases where the user was conscientious enough to attempt to add the right markup, which is facilitated by tools such as "Copy for Forum (Markdown)", they often still don't get it quite right. So it is worthwhile to make efforts to make it less likely for the markup to be inadvertently invalidated. "Fenced code block" markup must be on its own lines before and after the code content. Someone not familiar with Markdown won't know this fact and may simply paste the content copied via "Copy for Forum (Markdown)" without manually adding a newline before and after. Since the code content is preceded and succeeded by a newline, they will not have any visual indication of a problem. Adding a newline before and after the content will ensure the markup is valid regardless of the context it is pasted into. In cases where the user did add a newline and this introduces a redundant line break in the forum post, it will not have any effect on the rendered content because the additional newlines are ignored by the renderer.
275 lines
9.2 KiB
TypeScript
275 lines
9.2 KiB
TypeScript
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution';
|
|
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
|
|
import { MonacoEditorService } from '@theia/monaco/lib/browser/monaco-editor-service';
|
|
import {
|
|
Contribution,
|
|
Command,
|
|
MenuModelRegistry,
|
|
KeybindingRegistry,
|
|
CommandRegistry,
|
|
} from './contribution';
|
|
import { ArduinoMenus } from '../menu/arduino-menus';
|
|
import { nls } from '@theia/core/lib/common';
|
|
import type { ICodeEditor } from '@theia/monaco-editor-core/esm/vs/editor/browser/editorBrowser';
|
|
import type { StandaloneCodeEditor } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneCodeEditor';
|
|
|
|
// TODO: [macOS]: to remove `Start Dictation...` and `Emoji & Symbol` see this thread: https://github.com/electron/electron/issues/8283#issuecomment-269522072
|
|
// Depends on https://github.com/eclipse-theia/theia/pull/7964
|
|
@injectable()
|
|
export class EditContributions extends Contribution {
|
|
@inject(MonacoEditorService)
|
|
private readonly codeEditorService: MonacoEditorService;
|
|
|
|
@inject(ClipboardService)
|
|
private readonly clipboardService: ClipboardService;
|
|
|
|
override registerCommands(registry: CommandRegistry): void {
|
|
registry.registerCommand(EditContributions.Commands.GO_TO_LINE, {
|
|
execute: () => this.run('editor.action.gotoLine'),
|
|
});
|
|
registry.registerCommand(EditContributions.Commands.TOGGLE_COMMENT, {
|
|
execute: () => this.run('editor.action.commentLine'),
|
|
});
|
|
registry.registerCommand(EditContributions.Commands.INDENT_LINES, {
|
|
execute: () => this.run('editor.action.indentLines'),
|
|
});
|
|
registry.registerCommand(EditContributions.Commands.OUTDENT_LINES, {
|
|
execute: () => this.run('editor.action.outdentLines'),
|
|
});
|
|
registry.registerCommand(EditContributions.Commands.FIND, {
|
|
execute: () => this.run('actions.find'),
|
|
});
|
|
registry.registerCommand(EditContributions.Commands.FIND_NEXT, {
|
|
execute: () => this.run('editor.action.nextMatchFindAction'),
|
|
});
|
|
registry.registerCommand(EditContributions.Commands.FIND_PREVIOUS, {
|
|
execute: () => this.run('editor.action.previousMatchFindAction'),
|
|
});
|
|
registry.registerCommand(EditContributions.Commands.USE_FOR_FIND, {
|
|
execute: () => this.run('editor.action.previousSelectionMatchFindAction'),
|
|
});
|
|
/* Tools */ registry.registerCommand(
|
|
EditContributions.Commands.AUTO_FORMAT,
|
|
{ execute: () => this.run('editor.action.formatDocument') }
|
|
);
|
|
registry.registerCommand(EditContributions.Commands.COPY_FOR_FORUM, {
|
|
execute: async () => {
|
|
const value = await this.currentValue();
|
|
if (value !== undefined) {
|
|
this.clipboardService.writeText(`
|
|
\`\`\`cpp
|
|
${value}
|
|
\`\`\`
|
|
`);
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
override registerMenus(registry: MenuModelRegistry): void {
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, {
|
|
commandId: CommonCommands.CUT.id,
|
|
order: '0',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, {
|
|
commandId: CommonCommands.COPY.id,
|
|
order: '1',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, {
|
|
commandId: EditContributions.Commands.COPY_FOR_FORUM.id,
|
|
label: nls.localize(
|
|
'arduino/editor/copyForForum',
|
|
'Copy for Forum (Markdown)'
|
|
),
|
|
order: '2',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, {
|
|
commandId: CommonCommands.PASTE.id,
|
|
order: '3',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, {
|
|
commandId: CommonCommands.SELECT_ALL.id,
|
|
order: '4',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, {
|
|
commandId: EditContributions.Commands.GO_TO_LINE.id,
|
|
label: nls.localize(
|
|
'vscode/standaloneStrings/gotoLineActionLabel',
|
|
'Go to Line...'
|
|
),
|
|
order: '5',
|
|
});
|
|
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, {
|
|
commandId: EditContributions.Commands.TOGGLE_COMMENT.id,
|
|
label: nls.localize(
|
|
'arduino/editor/commentUncomment',
|
|
'Comment/Uncomment'
|
|
),
|
|
order: '0',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, {
|
|
commandId: EditContributions.Commands.INDENT_LINES.id,
|
|
label: nls.localize('arduino/editor/increaseIndent', 'Increase Indent'),
|
|
order: '1',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, {
|
|
commandId: EditContributions.Commands.OUTDENT_LINES.id,
|
|
label: nls.localize('arduino/editor/decreaseIndent', 'Decrease Indent'),
|
|
order: '2',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, {
|
|
commandId: EditContributions.Commands.AUTO_FORMAT.id,
|
|
label: nls.localize('arduino/editor/autoFormat', 'Auto Format'),
|
|
order: '3',
|
|
});
|
|
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, {
|
|
commandId: EditContributions.Commands.FIND.id,
|
|
label: nls.localize('vscode/findController/startFindAction', 'Find'),
|
|
order: '0',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, {
|
|
commandId: EditContributions.Commands.FIND_NEXT.id,
|
|
label: nls.localize(
|
|
'vscode/findController/findNextMatchAction',
|
|
'Find Next'
|
|
),
|
|
order: '1',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, {
|
|
commandId: EditContributions.Commands.FIND_PREVIOUS.id,
|
|
label: nls.localize(
|
|
'vscode/findController/findPreviousMatchAction',
|
|
'Find Previous'
|
|
),
|
|
order: '2',
|
|
});
|
|
registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, {
|
|
commandId: EditContributions.Commands.USE_FOR_FIND.id,
|
|
label: nls.localize(
|
|
'vscode/findController/startFindWithSelectionAction',
|
|
'Use Selection for Find'
|
|
), // XXX: The Java IDE uses `Use Selection For Find`.
|
|
order: '3',
|
|
});
|
|
|
|
// `Tools`
|
|
registry.registerMenuAction(ArduinoMenus.TOOLS__MAIN_GROUP, {
|
|
commandId: EditContributions.Commands.AUTO_FORMAT.id,
|
|
label: nls.localize('arduino/editor/autoFormat', 'Auto Format'), // XXX: The Java IDE uses `Use Selection For Find`.
|
|
order: '0',
|
|
});
|
|
}
|
|
|
|
override registerKeybindings(registry: KeybindingRegistry): void {
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.COPY_FOR_FORUM.id,
|
|
keybinding: 'CtrlCmd+Shift+C',
|
|
when: 'editorFocus',
|
|
});
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.GO_TO_LINE.id,
|
|
keybinding: 'CtrlCmd+L',
|
|
when: 'editorFocus',
|
|
});
|
|
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.TOGGLE_COMMENT.id,
|
|
keybinding: 'CtrlCmd+/',
|
|
when: 'editorFocus',
|
|
});
|
|
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.FIND.id,
|
|
keybinding: 'CtrlCmd+F',
|
|
});
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.FIND_NEXT.id,
|
|
keybinding: 'CtrlCmd+G',
|
|
});
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.FIND_PREVIOUS.id,
|
|
keybinding: 'CtrlCmd+Shift+G',
|
|
});
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.USE_FOR_FIND.id,
|
|
keybinding: 'CtrlCmd+E',
|
|
});
|
|
|
|
// `Tools`
|
|
registry.registerKeybinding({
|
|
command: EditContributions.Commands.AUTO_FORMAT.id,
|
|
keybinding: 'CtrlCmd+T',
|
|
});
|
|
}
|
|
|
|
protected async current(): Promise<
|
|
ICodeEditor | StandaloneCodeEditor | undefined
|
|
> {
|
|
return (
|
|
this.codeEditorService.getFocusedCodeEditor() ||
|
|
this.codeEditorService.getActiveCodeEditor() ||
|
|
undefined
|
|
);
|
|
}
|
|
|
|
protected async currentValue(): Promise<string | undefined> {
|
|
const currentEditor = await this.current();
|
|
if (currentEditor) {
|
|
const selection = currentEditor.getSelection();
|
|
if (!selection || selection.isEmpty()) {
|
|
return currentEditor.getValue();
|
|
}
|
|
return currentEditor.getModel()?.getValueInRange(selection);
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
protected async run(commandId: string): Promise<any> {
|
|
const editor = await this.current();
|
|
if (editor) {
|
|
const action = editor.getAction(commandId);
|
|
if (action) {
|
|
return action.run();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export namespace EditContributions {
|
|
export namespace Commands {
|
|
export const COPY_FOR_FORUM: Command = {
|
|
id: 'arduino-copy-for-forum',
|
|
};
|
|
export const GO_TO_LINE: Command = {
|
|
id: 'arduino-go-to-line',
|
|
};
|
|
export const TOGGLE_COMMENT: Command = {
|
|
id: 'arduino-toggle-comment',
|
|
};
|
|
export const INDENT_LINES: Command = {
|
|
id: 'arduino-indent-lines',
|
|
};
|
|
export const OUTDENT_LINES: Command = {
|
|
id: 'arduino-outdent-lines',
|
|
};
|
|
export const FIND: Command = {
|
|
id: 'arduino-find',
|
|
};
|
|
export const FIND_NEXT: Command = {
|
|
id: 'arduino-find-next',
|
|
};
|
|
export const FIND_PREVIOUS: Command = {
|
|
id: 'arduino-find-previous',
|
|
};
|
|
export const USE_FOR_FIND: Command = {
|
|
id: 'arduino-for-find',
|
|
};
|
|
export const AUTO_FORMAT: Command = {
|
|
id: 'arduino-auto-format', // `Auto Format` should belong to `Tool`.
|
|
};
|
|
}
|
|
}
|