Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export const enUS = {
},
csv: {
error: 'Error',
parsingFailed: 'Failed to parse CSV. Please check file format.'
parsingFailed: 'Failed to parse CSV. Please check file format.',
parseWarning: 'CSV parse warning:'
},
settings: {
fieldSeparator: 'Field Separator',
Expand Down Expand Up @@ -45,4 +46,16 @@ export const enUS = {
moveColLeft: 'Move column left',
moveColRight: 'Move column right',
}
,
tableMessages: {
atLeastOneRow: 'At least one row must remain',
atLeastOneColumn: 'At least one column must remain'
}
,
notifications: {
undo: 'Undid last action',
noMoreUndo: 'There is nothing more to undo',
redo: 'Redid action',
noMoreRedo: 'There is nothing more to redo'
}
};
15 changes: 14 additions & 1 deletion src/i18n/zh-cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export const zhCN = {
},
csv: {
error: '错误',
parsingFailed: 'CSV解析失败,请检查文件格式'
parsingFailed: 'CSV解析失败,请检查文件格式',
parseWarning: 'CSV解析提示:'
},
settings: {
fieldSeparator: '字段分隔符',
Expand Down Expand Up @@ -47,4 +48,16 @@ export const zhCN = {
moveColLeft: '向左移动一列',
moveColRight: '向右移动一列',
}
,
tableMessages: {
atLeastOneRow: '至少需要保留一行',
atLeastOneColumn: '至少需要保留一列'
}
,
notifications: {
undo: '已撤销上一步操作',
noMoreUndo: '没有更多可撤销的操作',
redo: '已重做操作',
noMoreRedo: '没有更多可重做的操作'
}
};
8 changes: 4 additions & 4 deletions src/utils/csv-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ export class CSVUtils {
const parseResult: any = Papa.parse(csvString, parseConfig as any);

if (parseResult.errors && parseResult.errors.length > 0) {
console.warn("CSV解析警告:", parseResult.errors);
new Notice(`CSV解析提示: ${parseResult.errors[0].message}`);
console.warn("CSV parse warnings:", parseResult.errors);
new Notice(`${i18n.t("csv.parseWarning")} ${parseResult.errors[0].message}`);
}

return parseResult.data as string[][];
} catch (error) {
console.error("CSV解析错误:", error);
new Notice(`${i18n.t("csv.error")}: CSV解析失败,请检查文件格式`);
console.error("CSV parse error:", error);
new Notice(i18n.t("csv.parsingFailed"));
return [[""]];
}
}
Expand Down
9 changes: 5 additions & 4 deletions src/utils/history-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Notice } from "obsidian";
import { i18n } from "../i18n";

export class HistoryManager<T> {
private history: T[] = [];
Expand Down Expand Up @@ -38,10 +39,10 @@ export class HistoryManager<T> {
undo(): T | null {
if (this.canUndo()) {
this.currentIndex--;
new Notice("已撤销上一步操作");
new Notice(i18n.t("notifications.undo"));
return this.getCurrentState();
} else {
new Notice("没有更多可撤销的操作");
new Notice(i18n.t("notifications.noMoreUndo"));
return null;
}
}
Expand All @@ -52,10 +53,10 @@ export class HistoryManager<T> {
redo(): T | null {
if (this.canRedo()) {
this.currentIndex++;
new Notice("已重做操作");
new Notice(i18n.t("notifications.redo"));
return this.getCurrentState();
} else {
new Notice("没有更多可重做的操作");
new Notice(i18n.t("notifications.noMoreRedo"));
return null;
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/utils/table-utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Notice } from "obsidian";
import { i18n } from "../i18n";

export class TableUtils {
/**
Expand Down Expand Up @@ -42,7 +43,7 @@ export class TableUtils {
*/
static deleteRow(tableData: string[][]): string[][] {
if (tableData.length <= 1) {
new Notice("至少需要保留一行");
new Notice(i18n.t("tableMessages.atLeastOneRow"));
return tableData;
}

Expand All @@ -61,7 +62,7 @@ export class TableUtils {
*/
static deleteColumn(tableData: string[][]): string[][] {
if (!tableData[0] || tableData[0].length <= 1) {
new Notice("至少需要保留一列");
new Notice(i18n.t("tableMessages.atLeastOneColumn"));
return tableData;
}

Expand Down
3 changes: 3 additions & 0 deletions src/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,9 @@ export class CSVView extends TextFileView {
document,
"keydown",
(event: KeyboardEvent) => {
// Only handle undo/redo when this view is the active leaf
if (this.app.workspace.activeLeaf !== this.leaf) return;

// 检测Ctrl+Z (或Mac上的Cmd+Z)
if ((event.ctrlKey || event.metaKey) && event.key === "z") {
if (event.shiftKey) {
Expand Down
50 changes: 50 additions & 0 deletions test/history-manager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { TableHistoryManager } from "../src/utils/history-manager";
import { Notice } from "obsidian";
import { i18n } from "../src/i18n";

beforeEach(() => {
// reset Notice mock
(Notice as any).mockClear && (Notice as any).mockClear();
});

test('undo on empty history shows noMoreUndo message', () => {
const hm = new TableHistoryManager([["a"]], 10);
// Initially only one state, cannot undo
const res = hm.undo();
expect(res).toBeNull();
expect(Notice).toHaveBeenCalledTimes(1);
expect((Notice as any).mock.calls[0][0]).toBe(i18n.t('notifications.noMoreUndo'));
});

test('undo when available shows undo message', () => {
const hm = new TableHistoryManager([["a"]], 10);
hm.push([["b"]]);
// Now we can undo
const res = hm.undo();
expect(res).toEqual([["a"]]);
expect(Notice).toHaveBeenCalledTimes(1);
expect((Notice as any).mock.calls[0][0]).toBe(i18n.t('notifications.undo'));
});

test('redo on no-op shows noMoreRedo message', () => {
const hm = new TableHistoryManager([["a"]], 10);
// Nothing to redo
const res = hm.redo();
expect(res).toBeNull();
expect(Notice).toHaveBeenCalledTimes(1);
expect((Notice as any).mock.calls[0][0]).toBe(i18n.t('notifications.noMoreRedo'));
});

test('redo when available shows redo message', () => {
const hm = new TableHistoryManager([["a"]], 10);
hm.push([["b"]]);
// undo back to first
const u = hm.undo();
expect(u).toEqual([["a"]]);
// redo
const r = hm.redo();
expect(r).toEqual([["b"]]);
// Two notices were called (undo, redo)
expect(Notice).toHaveBeenCalledTimes(2);
expect((Notice as any).mock.calls[1][0]).toBe(i18n.t('notifications.redo'));
});