Skip to content

Commit 40d1ce8

Browse files
committed
fix(excmds): clear excmd misuse notification after successful execution
1 parent e4422b1 commit 40d1ce8

4 files changed

Lines changed: 256 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ dist/
77
compile_commands.json
88
.envrc.local
99
/src/glide.ts
10+
.vscode/

src/glide/browser/base/content/browser-commandline.mts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,21 @@ export class TabsCompletionSource implements GlideCompletionSource<TabCompletion
214214
],
215215
}),
216216

217-
async accept() {
218-
gBrowser.selectedTab = tab;
217+
async accept(ctx) {
218+
const input = ctx.input.trim();
219+
const parts = input.split(" ");
220+
const arg = parts[1];
221+
222+
// User typed "tab " with no arg - select the focused tab from completion list
223+
if (arg === undefined || arg === "") {
224+
gBrowser.selectedTab = tab;
225+
GlideBrowser.remove_notification("glide-excmd-error");
226+
return;
227+
}
228+
229+
// User typed "tab <something>" - execute through GlideExcmds
230+
// This handles both valid indices and invalid input (which will show an error)
231+
await GlideExcmds.execute(input as any);
219232
},
220233
async delete() {
221234
gBrowser.removeTab(this.tab);

src/glide/browser/base/content/browser-excmds.mts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,17 @@ class GlideExcmdsClass {
106106
command: glide.ExcmdValue,
107107
props?: SetOptional<ExecuteProps, "args">,
108108
): Promise<void> {
109+
const command_name = typeof command === "string" ? extract_command_name(command) : command.name;
110+
109111
try {
110112
await this.#execute(command, {
111113
...props,
112114
args: { ...this.#parse_args(command), tab_id: GlideBrowser.active_tab_id, ...props?.args },
113115
});
116+
117+
if (!command_name.includes("commandline_")) {
118+
GlideBrowser.remove_notification("glide-excmd-error");
119+
}
114120
} catch (err) {
115121
GlideBrowser._log.error(err);
116122

src/glide/browser/base/content/test/commandline/browser_commandline.ts

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,3 +647,237 @@ add_task(async function test_non_command_not_suggested() {
647647
is(GlideTestUtils.commandline.visible_rows().length, GlideBrowser.commandline_excmds.length);
648648
});
649649
});
650+
651+
add_task(async function test_error_notification_tab_missing_args() {
652+
await GlideTestUtils.reload_config(function _() {});
653+
654+
await BrowserTestUtils.withNewTab(FILE, async () => {
655+
await keys(":tab<CR>");
656+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
657+
658+
const notification = gNotificationBox.getNotificationWithValue("glide-excmd-error")!;
659+
ok(
660+
notification.shadowRoot.querySelector(".message")?.textContent?.includes("tab_index"),
661+
"error message should mention missing 'tab_index' argument",
662+
);
663+
gNotificationBox.removeNotification(notification);
664+
});
665+
});
666+
667+
add_task(async function test_error_notification_tab_invalid_index() {
668+
await GlideTestUtils.reload_config(function _() {});
669+
670+
await BrowserTestUtils.withNewTab(FILE, async () => {
671+
await keys(":tab 999<CR>");
672+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
673+
674+
const notification = gNotificationBox.getNotificationWithValue("glide-excmd-error")!;
675+
ok(
676+
notification.shadowRoot.querySelector(".message")?.textContent?.includes("could not find a tab"),
677+
"error message should indicate tab not found",
678+
);
679+
gNotificationBox.removeNotification(notification);
680+
});
681+
});
682+
683+
add_task(async function test_error_notification_set_missing_args() {
684+
await GlideTestUtils.reload_config(function _() {});
685+
686+
await BrowserTestUtils.withNewTab(FILE, async () => {
687+
await keys(":set<CR>");
688+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
689+
690+
gNotificationBox.removeNotification(gNotificationBox.getNotificationWithValue("glide-excmd-error")!);
691+
});
692+
});
693+
694+
add_task(async function test_error_notification_set_invalid_option() {
695+
await GlideTestUtils.reload_config(function _() {});
696+
697+
await BrowserTestUtils.withNewTab(FILE, async () => {
698+
await keys(":set invalid_option_name 123<CR>");
699+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
700+
701+
const notification = gNotificationBox.getNotificationWithValue("glide-excmd-error")!;
702+
ok(
703+
notification.shadowRoot.querySelector(".message")?.textContent?.includes("not a valid option"),
704+
"error message should indicate invalid option",
705+
);
706+
gNotificationBox.removeNotification(notification);
707+
});
708+
});
709+
710+
add_task(async function test_error_notification_mode_change_missing_args() {
711+
await GlideTestUtils.reload_config(function _() {});
712+
713+
await BrowserTestUtils.withNewTab(FILE, async () => {
714+
await keys(":mode_change<CR>");
715+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
716+
717+
gNotificationBox.removeNotification(gNotificationBox.getNotificationWithValue("glide-excmd-error")!);
718+
});
719+
});
720+
721+
add_task(async function test_error_notification_keys_missing_args() {
722+
await GlideTestUtils.reload_config(function _() {});
723+
724+
await BrowserTestUtils.withNewTab(FILE, async () => {
725+
await keys(":keys<CR>");
726+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
727+
728+
const notification = gNotificationBox.getNotificationWithValue("glide-excmd-error")!;
729+
ok(
730+
notification.shadowRoot.querySelector(".message")?.textContent?.includes("keyseq"),
731+
"error message should mention missing 'keyseq' argument",
732+
);
733+
gNotificationBox.removeNotification(notification);
734+
});
735+
});
736+
737+
add_task(async function test_error_notification_unmap_missing_args() {
738+
await GlideTestUtils.reload_config(function _() {});
739+
740+
await BrowserTestUtils.withNewTab(FILE, async () => {
741+
await keys(":unmap<CR>");
742+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
743+
744+
const notification = gNotificationBox.getNotificationWithValue("glide-excmd-error")!;
745+
ok(
746+
notification.shadowRoot.querySelector(".message")?.textContent?.includes("lhs"),
747+
"error message should mention missing 'lhs' argument",
748+
);
749+
gNotificationBox.removeNotification(notification);
750+
});
751+
});
752+
753+
add_task(async function test_error_notification_caret_move_missing_args() {
754+
await GlideTestUtils.reload_config(function _() {});
755+
756+
await BrowserTestUtils.withNewTab(FILE, async () => {
757+
await keys(":caret_move<CR>");
758+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
759+
760+
const notification = gNotificationBox.getNotificationWithValue("glide-excmd-error")!;
761+
ok(
762+
notification.shadowRoot.querySelector(".message")?.textContent?.includes("direction"),
763+
"error message should mention missing 'direction' argument",
764+
);
765+
gNotificationBox.removeNotification(notification);
766+
});
767+
});
768+
769+
add_task(async function test_error_notification_cleared_tab_succeeds() {
770+
await GlideTestUtils.reload_config(function _() {});
771+
772+
await BrowserTestUtils.withNewTab(FILE, async () => {
773+
await keys(":tab<CR>");
774+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
775+
776+
await keys(":tab 0<CR>");
777+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error") === null).ok();
778+
779+
is(
780+
gNotificationBox.getNotificationWithValue("glide-excmd-error"),
781+
null,
782+
"error notification should be cleared after successful tab command",
783+
);
784+
});
785+
});
786+
787+
add_task(async function test_error_notification_cleared_mode_change_succeeds() {
788+
await GlideTestUtils.reload_config(function _() {});
789+
790+
await BrowserTestUtils.withNewTab(FILE, async () => {
791+
await keys(":mode_change<CR>");
792+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
793+
794+
await keys(":mode_change normal<CR>");
795+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error") === null).ok();
796+
797+
is(
798+
gNotificationBox.getNotificationWithValue("glide-excmd-error"),
799+
null,
800+
"error notification should be cleared after successful mode_change command",
801+
);
802+
});
803+
});
804+
805+
add_task(async function test_error_notification_cleared_by_different_command() {
806+
await GlideTestUtils.reload_config(function _() {});
807+
808+
await BrowserTestUtils.withNewTab(FILE, async () => {
809+
await keys(":tab<CR>");
810+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
811+
812+
await keys(":reload<CR>");
813+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error") === null).ok();
814+
815+
is(
816+
gNotificationBox.getNotificationWithValue("glide-excmd-error"),
817+
null,
818+
"error notification should be cleared after a different successful command",
819+
);
820+
});
821+
});
822+
823+
add_task(async function test_error_notification_cleared_by_different_command_with_args() {
824+
await GlideTestUtils.reload_config(function _() {});
825+
826+
await BrowserTestUtils.withNewTab(FILE, async () => {
827+
await keys(":set<CR>");
828+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
829+
830+
await keys(":mode_change normal<CR>");
831+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error") === null).ok();
832+
833+
is(
834+
gNotificationBox.getNotificationWithValue("glide-excmd-error"),
835+
null,
836+
"error notification should be cleared after a different successful command with args",
837+
);
838+
});
839+
});
840+
841+
add_task(async function test_error_notification_cleared_via_tab_completion() {
842+
await GlideTestUtils.reload_config(function _() {});
843+
844+
await BrowserTestUtils.withNewTab(FILE, async () => {
845+
await keys(":tab<CR>");
846+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
847+
848+
await GlideTestUtils.commandline.open();
849+
await keys("tab ");
850+
await waiter(() => GlideTestUtils.commandline.current_source_header()).is("tabs");
851+
await waiter(() => GlideTestUtils.commandline.visible_rows().length > 0).ok();
852+
await keys("<CR>");
853+
854+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error") === null).ok();
855+
856+
is(
857+
gNotificationBox.getNotificationWithValue("glide-excmd-error"),
858+
null,
859+
"error notification should be cleared after selecting tab via completion",
860+
);
861+
});
862+
});
863+
864+
add_task(async function test_multiple_errors_cleared_by_one_success() {
865+
await GlideTestUtils.reload_config(function _() {});
866+
867+
await BrowserTestUtils.withNewTab(FILE, async () => {
868+
await keys(":tab<CR>");
869+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
870+
871+
await keys(":set<CR>");
872+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error")).ok();
873+
874+
await keys(":tab 0<CR>");
875+
await waiter(() => gNotificationBox.getNotificationWithValue("glide-excmd-error") === null).ok();
876+
877+
is(
878+
gNotificationBox.getNotificationWithValue("glide-excmd-error"),
879+
null,
880+
"error notification should be cleared after any successful command",
881+
);
882+
});
883+
});

0 commit comments

Comments
 (0)