mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
Add Icon / HotKey to Delete Line (Cmd-D) (#214)
* work on cmd-d to delete a selected line * call stoppropagation when code.tsx captures keyboard input * finish up with line delete. add a trash icon to line. prevent delete when cmd is running (show error msg)
This commit is contained in:
parent
f6a6068674
commit
8ac1943d56
@ -596,6 +596,10 @@
|
||||
gap: 4px;
|
||||
align-self: stretch;
|
||||
width: 100%;
|
||||
|
||||
.settings-input .hotkey {
|
||||
color: @text-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,16 @@ import {
|
||||
Screen,
|
||||
Session,
|
||||
} from "../../../model/model";
|
||||
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage, Modal, Dropdown, Tooltip } from "../common";
|
||||
import {
|
||||
Toggle,
|
||||
InlineSettingsTextEdit,
|
||||
SettingsError,
|
||||
InfoMessage,
|
||||
Modal,
|
||||
Dropdown,
|
||||
Tooltip,
|
||||
Button,
|
||||
} from "../common";
|
||||
import { LineType, RendererPluginType, ClientDataType, CommandRtnType, RemoteType } from "../../../types/types";
|
||||
import { PluginModel } from "../../../plugins/plugins";
|
||||
import * as util from "../../../util/util";
|
||||
@ -632,12 +641,6 @@ class LineSettingsModal extends React.Component<{}, {}> {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Archived</div>
|
||||
<div className="settings-input">
|
||||
<Toggle checked={!!line.archived} onChange={this.handleChangeArchived} />
|
||||
</div>
|
||||
</div>
|
||||
<SettingsError errorMessage={this.errorMessage} />
|
||||
<div style={{ height: 50 }} />
|
||||
</div>
|
||||
|
@ -354,6 +354,12 @@ class LineCmd extends React.Component<
|
||||
GlobalCommandRunner.lineBookmark(line.lineid);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickDelete() {
|
||||
let { line } = this.props;
|
||||
GlobalCommandRunner.lineDelete(line.lineid, true);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickMinimize() {
|
||||
mobx.action(() => {
|
||||
@ -659,6 +665,9 @@ class LineCmd extends React.Component<
|
||||
{this.renderMeta1(cmd)}
|
||||
<If condition={!hidePrompt}>{this.renderCmdText(cmd)}</If>
|
||||
</div>
|
||||
<div key="delete" title="Delete Line (⌘D)" className="line-icon" onClick={this.clickDelete}>
|
||||
<i className="fa-sharp fa-regular fa-trash" />
|
||||
</div>
|
||||
<div
|
||||
key="bookmark"
|
||||
title="Bookmark"
|
||||
|
@ -3365,7 +3365,7 @@ class Model {
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
docKeyDownHandler(e: any) {
|
||||
docKeyDownHandler(e: KeyboardEvent) {
|
||||
if (isModKeyPress(e)) {
|
||||
return;
|
||||
}
|
||||
@ -3427,6 +3427,37 @@ class Model {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e.code == "KeyD" && e.getModifierState("Meta")) {
|
||||
let ranDelete = this.deleteActiveLine();
|
||||
if (ranDelete) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteActiveLine(): boolean {
|
||||
let activeScreen = this.getActiveScreen();
|
||||
if (activeScreen == null || activeScreen.getFocusType() != "cmd") {
|
||||
return false;
|
||||
}
|
||||
let selectedLine = activeScreen.selectedLine.get();
|
||||
if (selectedLine == null || selectedLine <= 0) {
|
||||
return false;
|
||||
}
|
||||
let line = activeScreen.getLineByNum(selectedLine);
|
||||
if (line == null) {
|
||||
return false;
|
||||
}
|
||||
let cmd = activeScreen.getCmd(line);
|
||||
if (cmd != null) {
|
||||
if (cmd.isRunning()) {
|
||||
let info: T.InfoType = { infomsg: "Cannot delete a running command" };
|
||||
this.inputModel.flashInfoMsg(info, 2000);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
GlobalCommandRunner.lineDelete(String(selectedLine), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
clearModals(): boolean {
|
||||
@ -4311,6 +4342,10 @@ class CommandRunner {
|
||||
return GlobalModel.submitCommand("line", "archive", [lineArg, archiveStr], kwargs, false);
|
||||
}
|
||||
|
||||
lineDelete(lineArg: string, interactive: boolean): Promise<CommandRtnType> {
|
||||
return GlobalModel.submitCommand("line", "delete", [lineArg], { nohist: "1" }, interactive);
|
||||
}
|
||||
|
||||
lineSet(lineArg: string, opts: { renderer?: string }): Promise<CommandRtnType> {
|
||||
let kwargs = { nohist: "1" };
|
||||
if ("renderer" in opts) {
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
import * as React from "react";
|
||||
import * as T from "../../types/types";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import Editor, { Monaco } from "@monaco-editor/react";
|
||||
import type * as MonacoTypes from "monaco-editor/esm/vs/editor/editor.api";
|
||||
import { Markdown } from "../../app/common/common";
|
||||
import { GlobalModel, GlobalCommandRunner } from "../../model/model";
|
||||
import Split from "react-split-it";
|
||||
@ -146,21 +147,24 @@ class SourceCodeRenderer extends React.Component<
|
||||
}
|
||||
};
|
||||
|
||||
handleEditorDidMount = (editor, monaco) => {
|
||||
handleEditorDidMount = (editor: MonacoTypes.editor.IStandaloneCodeEditor, monaco: Monaco) => {
|
||||
this.monacoEditor = editor;
|
||||
this.setInitialLanguage(editor);
|
||||
this.setEditorHeight();
|
||||
editor.onKeyDown((e) => {
|
||||
if (e.code === "KeyS" && (e.ctrlKey || e.metaKey) && this.state.isSave) {
|
||||
editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
|
||||
if (e.code === "KeyS" && e.metaKey && this.state.isSave) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.doSave();
|
||||
}
|
||||
if (e.code === "KeyD" && (e.ctrlKey || e.metaKey)) {
|
||||
if (e.code === "KeyD" && e.metaKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.doClose();
|
||||
}
|
||||
if (e.code === "KeyP" && (e.ctrlKey || e.metaKey)) {
|
||||
if (e.code === "KeyP" && e.metaKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.togglePreview();
|
||||
}
|
||||
});
|
||||
|
@ -3440,7 +3440,7 @@ func LineDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s
|
||||
}
|
||||
err = sstore.DeleteLinesByIds(ctx, ids.ScreenId, lineIds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:delete error purging lines: %v", err)
|
||||
return nil, fmt.Errorf("/line:delete error deleting lines: %v", err)
|
||||
}
|
||||
update := &sstore.ModelUpdate{}
|
||||
for _, lineId := range lineIds {
|
||||
@ -3451,6 +3451,11 @@ func LineDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s
|
||||
}
|
||||
update.Lines = append(update.Lines, lineObj)
|
||||
}
|
||||
screen, err := sstore.FixupScreenSelectedLine(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:delete error fixing up screen: %v", err)
|
||||
}
|
||||
update.Screens = []*sstore.ScreenType{screen}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
|
@ -2039,6 +2039,29 @@ func SetLineArchivedById(ctx context.Context, screenId string, lineId string, ar
|
||||
return txErr
|
||||
}
|
||||
|
||||
// returns updated screen (only if updated)
|
||||
func FixupScreenSelectedLine(ctx context.Context, screenId string) (*ScreenType, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ScreenType, error) {
|
||||
query := `SELECT selectedline FROM screen WHERE screenid = ?`
|
||||
sline := tx.GetInt(query, screenId)
|
||||
query = `SELECT linenum FROM line WHERE screenid = ? AND linenum = ?`
|
||||
if tx.Exists(query, screenId, sline) {
|
||||
// selected line is valid
|
||||
return nil, nil
|
||||
}
|
||||
query = `SELECT min(linenum) FROM line WHERE screenid = ? AND linenum > ?`
|
||||
newSLine := tx.GetInt(query, screenId, sline)
|
||||
if newSLine == 0 {
|
||||
query = `SELECT max(linenum) FROM line WHERE screenid = ? AND linenum < ?`
|
||||
newSLine = tx.GetInt(query, screenId, sline)
|
||||
}
|
||||
// newSLine might be 0, but that's ok (because that means there are no lines)
|
||||
query = `UPDATE screen SET selectedline = ? WHERE screenid = ?`
|
||||
tx.Exec(query, newSLine, screenId)
|
||||
return GetScreenById(tx.Context(), screenId)
|
||||
})
|
||||
}
|
||||
|
||||
func DeleteLinesByIds(ctx context.Context, screenId string, lineIds []string) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
isWS := isWebShare(tx, screenId)
|
||||
@ -2046,9 +2069,8 @@ func DeleteLinesByIds(ctx context.Context, screenId string, lineIds []string) er
|
||||
query := `SELECT status FROM cmd WHERE screenid = ? AND lineid = ?`
|
||||
cmdStatus := tx.GetString(query, screenId, lineId)
|
||||
if cmdStatus == CmdStatusRunning {
|
||||
return fmt.Errorf("cannot delete line[%s:%s], cmd is running", screenId, lineId)
|
||||
return fmt.Errorf("cannot delete line[%s], cmd is running", lineId)
|
||||
}
|
||||
|
||||
query = `DELETE FROM line WHERE screenid = ? AND lineid = ?`
|
||||
tx.Exec(query, screenId, lineId)
|
||||
query = `DELETE FROM cmd WHERE screenid = ? AND lineid = ?`
|
||||
@ -2056,7 +2078,6 @@ func DeleteLinesByIds(ctx context.Context, screenId string, lineIds []string) er
|
||||
// don't delete history anymore, just remove lineid reference
|
||||
query = `UPDATE history SET lineid = '', linenum = 0 WHERE screenid = ? AND lineid = ?`
|
||||
tx.Exec(query, screenId, lineId)
|
||||
|
||||
if isWS {
|
||||
insertScreenLineUpdate(tx, screenId, lineId, UpdateType_LineDel)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user