mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-31 18:18:02 +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;
|
gap: 4px;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
.settings-input .hotkey {
|
||||||
|
color: @text-secondary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,16 @@ import {
|
|||||||
Screen,
|
Screen,
|
||||||
Session,
|
Session,
|
||||||
} from "../../../model/model";
|
} 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 { LineType, RendererPluginType, ClientDataType, CommandRtnType, RemoteType } from "../../../types/types";
|
||||||
import { PluginModel } from "../../../plugins/plugins";
|
import { PluginModel } from "../../../plugins/plugins";
|
||||||
import * as util from "../../../util/util";
|
import * as util from "../../../util/util";
|
||||||
@ -632,12 +641,6 @@ class LineSettingsModal extends React.Component<{}, {}> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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} />
|
<SettingsError errorMessage={this.errorMessage} />
|
||||||
<div style={{ height: 50 }} />
|
<div style={{ height: 50 }} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -354,6 +354,12 @@ class LineCmd extends React.Component<
|
|||||||
GlobalCommandRunner.lineBookmark(line.lineid);
|
GlobalCommandRunner.lineBookmark(line.lineid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@boundMethod
|
||||||
|
clickDelete() {
|
||||||
|
let { line } = this.props;
|
||||||
|
GlobalCommandRunner.lineDelete(line.lineid, true);
|
||||||
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
clickMinimize() {
|
clickMinimize() {
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
@ -659,6 +665,9 @@ class LineCmd extends React.Component<
|
|||||||
{this.renderMeta1(cmd)}
|
{this.renderMeta1(cmd)}
|
||||||
<If condition={!hidePrompt}>{this.renderCmdText(cmd)}</If>
|
<If condition={!hidePrompt}>{this.renderCmdText(cmd)}</If>
|
||||||
</div>
|
</div>
|
||||||
|
<div key="delete" title="Delete Line (⌘D)" className="line-icon" onClick={this.clickDelete}>
|
||||||
|
<i className="fa-sharp fa-regular fa-trash" />
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
key="bookmark"
|
key="bookmark"
|
||||||
title="Bookmark"
|
title="Bookmark"
|
||||||
|
@ -3365,7 +3365,7 @@ class Model {
|
|||||||
// nothing for now
|
// nothing for now
|
||||||
}
|
}
|
||||||
|
|
||||||
docKeyDownHandler(e: any) {
|
docKeyDownHandler(e: KeyboardEvent) {
|
||||||
if (isModKeyPress(e)) {
|
if (isModKeyPress(e)) {
|
||||||
return;
|
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 {
|
clearModals(): boolean {
|
||||||
@ -4311,6 +4342,10 @@ class CommandRunner {
|
|||||||
return GlobalModel.submitCommand("line", "archive", [lineArg, archiveStr], kwargs, false);
|
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> {
|
lineSet(lineArg: string, opts: { renderer?: string }): Promise<CommandRtnType> {
|
||||||
let kwargs = { nohist: "1" };
|
let kwargs = { nohist: "1" };
|
||||||
if ("renderer" in opts) {
|
if ("renderer" in opts) {
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as T from "../../types/types";
|
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 { Markdown } from "../../app/common/common";
|
||||||
import { GlobalModel, GlobalCommandRunner } from "../../model/model";
|
import { GlobalModel, GlobalCommandRunner } from "../../model/model";
|
||||||
import Split from "react-split-it";
|
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.monacoEditor = editor;
|
||||||
this.setInitialLanguage(editor);
|
this.setInitialLanguage(editor);
|
||||||
this.setEditorHeight();
|
this.setEditorHeight();
|
||||||
editor.onKeyDown((e) => {
|
editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
|
||||||
if (e.code === "KeyS" && (e.ctrlKey || e.metaKey) && this.state.isSave) {
|
if (e.code === "KeyS" && e.metaKey && this.state.isSave) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
this.doSave();
|
this.doSave();
|
||||||
}
|
}
|
||||||
if (e.code === "KeyD" && (e.ctrlKey || e.metaKey)) {
|
if (e.code === "KeyD" && e.metaKey) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
this.doClose();
|
this.doClose();
|
||||||
}
|
}
|
||||||
if (e.code === "KeyP" && (e.ctrlKey || e.metaKey)) {
|
if (e.code === "KeyP" && e.metaKey) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
this.togglePreview();
|
this.togglePreview();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3440,7 +3440,7 @@ func LineDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s
|
|||||||
}
|
}
|
||||||
err = sstore.DeleteLinesByIds(ctx, ids.ScreenId, lineIds)
|
err = sstore.DeleteLinesByIds(ctx, ids.ScreenId, lineIds)
|
||||||
if err != nil {
|
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{}
|
update := &sstore.ModelUpdate{}
|
||||||
for _, lineId := range lineIds {
|
for _, lineId := range lineIds {
|
||||||
@ -3451,6 +3451,11 @@ func LineDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s
|
|||||||
}
|
}
|
||||||
update.Lines = append(update.Lines, lineObj)
|
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
|
return update, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2039,6 +2039,29 @@ func SetLineArchivedById(ctx context.Context, screenId string, lineId string, ar
|
|||||||
return txErr
|
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 {
|
func DeleteLinesByIds(ctx context.Context, screenId string, lineIds []string) error {
|
||||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||||
isWS := isWebShare(tx, screenId)
|
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 = ?`
|
query := `SELECT status FROM cmd WHERE screenid = ? AND lineid = ?`
|
||||||
cmdStatus := tx.GetString(query, screenId, lineId)
|
cmdStatus := tx.GetString(query, screenId, lineId)
|
||||||
if cmdStatus == CmdStatusRunning {
|
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 = ?`
|
query = `DELETE FROM line WHERE screenid = ? AND lineid = ?`
|
||||||
tx.Exec(query, screenId, lineId)
|
tx.Exec(query, screenId, lineId)
|
||||||
query = `DELETE FROM cmd WHERE screenid = ? AND 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
|
// don't delete history anymore, just remove lineid reference
|
||||||
query = `UPDATE history SET lineid = '', linenum = 0 WHERE screenid = ? AND lineid = ?`
|
query = `UPDATE history SET lineid = '', linenum = 0 WHERE screenid = ? AND lineid = ?`
|
||||||
tx.Exec(query, screenId, lineId)
|
tx.Exec(query, screenId, lineId)
|
||||||
|
|
||||||
if isWS {
|
if isWS {
|
||||||
insertScreenLineUpdate(tx, screenId, lineId, UpdateType_LineDel)
|
insertScreenLineUpdate(tx, screenId, lineId, UpdateType_LineDel)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user