From 7f2284654b9a365e61b1241d6b7c772839e1dd9d Mon Sep 17 00:00:00 2001 From: Maxime Jacquemin <maxime2.jacquemin@gmail.com> Date: Thu, 16 Sep 2021 16:25:44 +0200 Subject: [PATCH] [ivette] First steps for external code edition For now I have the following: - A new preference that allows to specify which command to launch to edit the source code in the user's favorite editor; - Spawn a new process that launch the editor on the current selection using the specified command. The keybinding used is <Ctrl-LeftClick>, exactly as the old GUI. However, there is a catch. First, the keybinding does not select a line before launching the external editor. Second, the only selection that is actually taken into consideration is the one done when we click on a function. --- ivette/src/frama-c/kernel/SourceCode.tsx | 15 ++++++++++++--- ivette/src/ivette/prefs.tsx | 17 +++++++++++++++++ ivette/src/renderer/Preferences.tsx | 13 +++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/ivette/src/frama-c/kernel/SourceCode.tsx b/ivette/src/frama-c/kernel/SourceCode.tsx index aaf770e7399..440f51a1ab9 100644 --- a/ivette/src/frama-c/kernel/SourceCode.tsx +++ b/ivette/src/frama-c/kernel/SourceCode.tsx @@ -28,7 +28,7 @@ import React from 'react'; import * as States from 'frama-c/states'; import * as Dome from 'dome'; -import { readFile } from 'dome/system'; +import * as System from 'dome/system'; import { RichTextBuffer } from 'dome/text/buffers'; import { Text } from 'dome/text/editors'; import { TitleBar } from 'ivette'; @@ -37,6 +37,7 @@ import { functions, markerInfo } from 'frama-c/api/kernel/ast'; import { Code } from 'dome/controls/labels'; import { Hfill } from 'dome/layout/boxes'; import * as Path from 'path'; +import * as Settings from 'dome/data/settings'; import 'codemirror/addon/selection/active-line'; import 'codemirror/addon/dialog/dialog.css'; @@ -86,12 +87,20 @@ export default function SourceCode() { // Updating the buffer content. const errorMsg = () => { D.error(`Fail to load source code file ${file}`); }; const onError = () => { if (file) errorMsg(); return ''; }; - const read = () => readFile(file).catch(onError); + const read = () => System.readFile(file).catch(onError); const text = React.useMemo(read, [file, onError]); const { result } = Dome.usePromise(text); React.useEffect(() => buffer.setValue(result), [buffer, result]); React.useEffect(() => buffer.setCursorOnTop(line), [buffer, line, result]); + const [command] = Settings.useGlobalSettings(Preferences.EditorCommand); + const launchEditor = () => { + const cmd = command.replace('\%s', file).replace('\%d', line.toString()); + const args = cmd.split(' '); + const prog = args.shift(); + if (prog) System.spawn(prog, args); + }; + // Building the React component. return ( <> @@ -109,7 +118,7 @@ export default function SourceCode() { selection={theMarker} lineNumbers={!!theFunction} styleActiveLine={!!theFunction} - extraKeys={{ 'Alt-F': 'findPersistent' }} + extraKeys={{ 'Ctrl-LeftClick': launchEditor }} readOnly /> </> diff --git a/ivette/src/ivette/prefs.tsx b/ivette/src/ivette/prefs.tsx index 71df4d94ca4..b4fd8e08190 100644 --- a/ivette/src/ivette/prefs.tsx +++ b/ivette/src/ivette/prefs.tsx @@ -127,3 +127,20 @@ export function useThemeButtons(props: ThemeProps): ThemeControls { } // -------------------------------------------------------------------------- +// --- Editor configuration +// -------------------------------------------------------------------------- + +export const EditorCommand = + new Settings.GString('Editor.Command', 'emacs +\%d \%s'); + +export interface EditorCommandProps { + command: Settings.GlobalSettings<string>; +} + +// function produceCommand(command: string, file: string, line: number): string { +// command.replace('\%s', file); +// command.replace('\%d', line.toString()); +// return ""; +// } + +// -------------------------------------------------------------------------- diff --git a/ivette/src/renderer/Preferences.tsx b/ivette/src/renderer/Preferences.tsx index a16aea3fdb2..b6696ab22ad 100644 --- a/ivette/src/renderer/Preferences.tsx +++ b/ivette/src/renderer/Preferences.tsx @@ -83,6 +83,16 @@ function ThemeFields(props: P.ThemeProps) { ); } +// -------------------------------------------------------------------------- +// --- Editor Command Forms +// -------------------------------------------------------------------------- +function EditorCommandFields(props : P.EditorCommandProps) { + const command = Forms.useDefined( + Forms.useValid(Settings.useGlobalSettings(props.command) + )); + return (<Forms.TextCodeField state={command} label="Command"/>); +} + // -------------------------------------------------------------------------- // --- Export Components // -------------------------------------------------------------------------- @@ -105,6 +115,9 @@ export default (() => ( wrapText={P.SourceWrapText} /> </Forms.Section> + <Forms.Section label="Editor Command" unfold> + <EditorCommandFields command={P.EditorCommand}/> + </Forms.Section> </Forms.Page> )); -- GitLab