Added tab type selection

This commit is contained in:
2025-04-25 00:03:06 +08:00
parent 8673b36f98
commit 3483ac4cf6
5 changed files with 54 additions and 21 deletions

View File

@@ -26,7 +26,10 @@ const editorStore = useEditorStore();
<input type="checkbox" :checked="editorStore.enableTabIndent" @change="editorStore.toggleTabIndent"/>
<span>Tab</span>
</label>
<span class="tab-size" title="Tab大小">
<span class="tab-type" title="Tab类型切换" @click="editorStore.toggleTabType">
{{ editorStore.tabType === 'spaces' ? '空格' : '制表符' }}
</span>
<span class="tab-size" title="Tab大小" v-if="editorStore.tabType === 'spaces'">
<button class="tab-btn" @click="editorStore.decreaseTabSize" :disabled="editorStore.tabSize <= 2">-</button>
<span>{{ editorStore.tabSize }}</span>
<button class="tab-btn" @click="editorStore.increaseTabSize" :disabled="editorStore.tabSize >= 8">+</button>
@@ -98,6 +101,17 @@ const editorStore = useEditorStore();
cursor: pointer;
}
}
.tab-type {
cursor: pointer;
padding: 0 3px;
border-radius: 3px;
background-color: rgba(255, 255, 255, 0.05);
&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
}
.tab-size {
display: flex;

View File

@@ -2,33 +2,35 @@ import {Compartment, Extension} from '@codemirror/state';
import {EditorView, keymap} from '@codemirror/view';
import {indentSelection} from '@codemirror/commands';
import {indentUnit} from '@codemirror/language';
import {TabType} from '@/stores/editor';
// Tab设置相关的compartment
export const tabSizeCompartment = new Compartment();
export const tabKeyCompartment = new Compartment();
// 自定义Tab键处理函数
export const tabHandler = (view: EditorView, tabSize: number): boolean => {
export const tabHandler = (view: EditorView, tabSize: number, tabType: TabType): boolean => {
// 如果有选中文本使用indentSelection
if (!view.state.selection.main.empty) {
return indentSelection(view);
}
// 创建相应数量的空格
const spaces = ' '.repeat(tabSize);
// 根据tabType创建缩进字符
const indent = tabType === 'spaces' ? ' '.repeat(tabSize) : '\t';
// 在光标位置插入空格
// 在光标位置插入缩进字符
const {state, dispatch} = view;
dispatch(state.update(state.replaceSelection(spaces), {scrollIntoView: true}));
dispatch(state.update(state.replaceSelection(indent), {scrollIntoView: true}));
return true;
};
// 获取Tab相关的扩展
export const getTabExtensions = (tabSize: number, enableTabIndent: boolean): Extension[] => {
export const getTabExtensions = (tabSize: number, enableTabIndent: boolean, tabType: TabType): Extension[] => {
const extensions: Extension[] = [];
// 设置缩进单位
extensions.push(tabSizeCompartment.of(indentUnit.of(' '.repeat(tabSize))));
// 根据tabType设置缩进单位
const indentStr = tabType === 'spaces' ? ' '.repeat(tabSize) : '\t';
extensions.push(tabSizeCompartment.of(indentUnit.of(indentStr)));
// 如果启用了Tab缩进添加自定义Tab键映射
if (enableTabIndent) {
@@ -36,7 +38,7 @@ export const getTabExtensions = (tabSize: number, enableTabIndent: boolean): Ext
tabKeyCompartment.of(
keymap.of([{
key: "Tab",
run: (view) => tabHandler(view, tabSize)
run: (view) => tabHandler(view, tabSize, tabType)
}])
)
);
@@ -51,20 +53,22 @@ export const getTabExtensions = (tabSize: number, enableTabIndent: boolean): Ext
export const updateTabConfig = (
view: EditorView | null,
tabSize: number,
enableTabIndent: boolean
enableTabIndent: boolean,
tabType: TabType
) => {
if (!view) return;
// 更新indentUnit配置
// 根据tabType更新indentUnit配置
const indentStr = tabType === 'spaces' ? ' '.repeat(tabSize) : '\t';
view.dispatch({
effects: tabSizeCompartment.reconfigure(indentUnit.of(' '.repeat(tabSize)))
effects: tabSizeCompartment.reconfigure(indentUnit.of(indentStr))
});
// 更新Tab键映射
const tabKeymap = enableTabIndent
? keymap.of([{
key: "Tab",
run: (view) => tabHandler(view, tabSize)
run: (view) => tabHandler(view, tabSize, tabType)
}])
: [];

View File

@@ -34,7 +34,8 @@ const createEditor = () => {
// 获取Tab相关扩展
const tabExtensions = getTabExtensions(
editorStore.tabSize,
editorStore.enableTabIndent
editorStore.enableTabIndent,
editorStore.tabType
);
// 创建统计信息更新扩展
@@ -83,13 +84,15 @@ const reconfigureTabSettings = () => {
updateTabConfig(
editorStore.editorView as EditorView,
editorStore.tabSize,
editorStore.enableTabIndent
editorStore.enableTabIndent,
editorStore.tabType
);
};
// 监听Tab设置变化
watch(() => editorStore.tabSize, reconfigureTabSettings);
watch(() => editorStore.enableTabIndent, reconfigureTabSettings);
watch(() => editorStore.tabType, reconfigureTabSettings);
onMounted(() => {
// 创建编辑器

View File

@@ -8,12 +8,12 @@ export const config = {
dark: true,
background: '#252B37',
foreground: '#9BB586',
selection: '#1A5888',
selectionMatch: 'rgba(26, 88, 136, 0.5)',
selection: '#3381c1',
selectionMatch: '#1A58887F',
cursor: '#F8F8F2',
dropdownBackground: '#282A36',
dropdownBorder: '#191A21',
activeLine: 'rgba(46, 51, 63, 0.6)',
activeLine: '#2E333F99',
lineNumber: '#676d7c',
lineNumberActive: '#F8F8F2',
lineNumberBackground: '#212731',

View File

@@ -13,6 +13,9 @@ const DEFAULT_TAB_SIZE = 4;
const MIN_TAB_SIZE = 2;
const MAX_TAB_SIZE = 8;
// Tab类型
export type TabType = 'spaces' | 'tab';
export const useEditorStore = defineStore('editor', () => {
// 状态
const documentStats = ref<DocumentStats>({
@@ -30,6 +33,8 @@ export const useEditorStore = defineStore('editor', () => {
const enableTabIndent = ref(true);
// Tab键大小
const tabSize = ref(DEFAULT_TAB_SIZE);
// Tab类型空格或制表符
const tabType = ref<TabType>('spaces');
// 方法
function setEditorView(view: EditorView | null) {
@@ -94,6 +99,11 @@ export const useEditorStore = defineStore('editor', () => {
tabSize.value -= 1;
}
}
// 切换Tab类型空格或制表符
function toggleTabType() {
tabType.value = tabType.value === 'spaces' ? 'tab' : 'spaces';
}
// 设置按钮操作
function openSettings() {
@@ -109,6 +119,7 @@ export const useEditorStore = defineStore('editor', () => {
fontSize,
enableTabIndent,
tabSize,
tabType,
// 方法
setEditorView,
@@ -120,12 +131,13 @@ export const useEditorStore = defineStore('editor', () => {
resetFontSize,
toggleTabIndent,
increaseTabSize,
decreaseTabSize
decreaseTabSize,
toggleTabType
};
}, {
persist: {
key: 'editor',
storage: localStorage,
pick: ['fontSize', 'encoding', 'enableTabIndent', 'tabSize']
pick: ['fontSize', 'encoding', 'enableTabIndent', 'tabSize', 'tabType']
}
});