Added dockerfile、lua prettier plugin

This commit is contained in:
2025-09-20 01:30:16 +08:00
parent 2ea3456ff7
commit c3670bb8cd
79 changed files with 3790 additions and 289 deletions

View File

@@ -6,36 +6,14 @@
import { EditorState, EditorSelection } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { Command } from "@codemirror/view";
import { SUPPORTED_LANGUAGES } from "./types";
import { LANGUAGES } from "./lang-parser/languages";
/**
* 构建块分隔符正则表达式
*/
const languageTokensMatcher = SUPPORTED_LANGUAGES.join("|");
const languageTokensMatcher = LANGUAGES.map(lang => lang.token).join("|");
const blockSeparatorRegex = new RegExp(`\\n∞∞∞(${languageTokensMatcher})(-a)?\\n`, "g");
/**
* 降级复制方法 - 使用传统的 document.execCommand
*/
function fallbackCopyToClipboard(text: string): boolean {
try {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
const result = document.execCommand('copy');
document.body.removeChild(textArea);
return result;
} catch (err) {
console.error('The downgrade replication method also failed:', err);
return false;
}
}
/**
* 获取被复制的范围和内容
*/
@@ -118,15 +96,9 @@ const copyCut = (view: EditorView, cut: boolean): boolean => {
let { text, ranges } = copiedRange(view.state);
// 将块分隔符替换为双换行符
text = text.replaceAll(blockSeparatorRegex, "\n\n");
// 使用现代剪贴板 API
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).catch(err => {
fallbackCopyToClipboard(text);
});
} else {
// 降级到传统方法
fallbackCopyToClipboard(text);
navigator.clipboard.writeText(text);
}
if (cut && !view.state.readOnly) {

View File

@@ -158,7 +158,6 @@ const blockLayer = layer({
markers.push(new RectangleMarker(
idx++ % 2 == 0 ? "block-even" : "block-odd",
0,
// 参考 Heynote 的精确计算方式
fromCoordsTop - (view.documentTop - view.documentPadding.top) - 1 - 6,
null, // 宽度在 CSS 中设置为 100%
(toCoordsBottom - fromCoordsTop) + 15,

View File

@@ -38,12 +38,16 @@ export const formatBlockContent = (view) => {
const performFormat = async () => {
let formattedContent
try {
// 格式化代码
const formatted = await prettier.format(content, {
// 构建格式化配置
const formatOptions = {
parser: language.prettier!.parser,
plugins: language.prettier!.plugins,
tabWidth: tabSize,
})
...language.prettier!.options,
}
// 格式化代码
const formatted = await prettier.format(content, formatOptions)
// 计算新光标位置
const cursorOffset = cursorAtEdge

View File

@@ -22,8 +22,8 @@ import {getBlockSelectExtensions} from './selectAll';
import {getCopyPasteExtensions} from './copyPaste';
import {moveLineDown, moveLineUp} from './moveLines';
import {getCodeBlockLanguageExtension} from './lang-parser';
import {createLanguageDetection} from './language-detection';
import {EditorOptions, SupportedLanguage} from './types';
import {createLanguageDetection} from './lang-detect';
import {SupportedLanguage} from './types';
/**
* 代码块扩展配置选项
@@ -127,7 +127,6 @@ export {
type Block,
type SupportedLanguage,
type CreateBlockOptions,
SUPPORTED_LANGUAGES
} from './types';
// 状态管理
@@ -187,10 +186,8 @@ export {
export {
getCodeBlockLanguageExtension,
getLanguage,
getLanguageTokens,
languageMapping,
LanguageInfo,
LANGUAGES as PARSER_LANGUAGES
} from './lang-parser';
// 语言检测
@@ -200,7 +197,7 @@ export {
detectLanguages,
levenshteinDistance,
type LanguageDetectionResult
} from './language-detection';
} from './lang-detect';
// 行号相关
export {getBlockLineFromPos, blockLineNumbers};

View File

@@ -61,18 +61,24 @@ const DEFAULT_CONFIG = {
};
/**
*
* ID到语言token的映射
*/
const SUPPORTED_LANGUAGES = new Set([
"json", "py", "html", "sql", "md", "java", "php", "css", "xml",
"cpp", "rs", "cs", "rb", "sh", "yaml", "toml", "go", "clj",
"ex", "erl", "js", "ts", "swift", "kt", "groovy", "ps1", "dart", "scala"
]);
function createDetectionMap(): Map<string, SupportedLanguage> {
const map = new Map<string, SupportedLanguage>();
LANGUAGES.forEach(lang => {
if (lang.detectIds) {
lang.detectIds.forEach(detectId => {
map.set(detectId, lang.token);
});
}
});
return map;
}
/**
*
* ID到语言token的映射
*/
const LANGUAGE_MAP = new Map(LANGUAGES.map(lang => [lang.token, lang.token]));
const DETECTION_MAP = createDetectionMap();
// ===== 工具函数 =====
@@ -253,14 +259,16 @@ export function createLanguageDetection(config: LanguageDetectionConfig = {}): V
try {
const result = await worker.detectLanguage(content);
if (result.confidence >= finalConfig.confidenceThreshold &&
result.language !== block.language.name &&
SUPPORTED_LANGUAGES.has(result.language) &&
LANGUAGE_MAP.has(result.language)) {
// 使用检测映射表将检测结果转换为我们支持的语言
const mappedLanguage = DETECTION_MAP.get(result.language);
if (mappedLanguage &&
result.confidence >= finalConfig.confidenceThreshold &&
mappedLanguage !== block.language.name) {
// 只有在用户没有撤销操作时才更改语言
if (redoDepth(state) === 0) {
changeLanguageTo(state, this.view.dispatch, block, result.language, true);
changeLanguageTo(state, this.view.dispatch, block, mappedLanguage, true);
}
}

View File

@@ -16,7 +16,6 @@ export {
LANGUAGES,
languageMapping,
getLanguage,
getLanguageTokens
} from './languages';
// 嵌套解析器

View File

@@ -28,6 +28,8 @@ import {groovy} from "@codemirror/legacy-modes/mode/groovy";
import {powerShell} from "@codemirror/legacy-modes/mode/powershell";
import {toml} from "@codemirror/legacy-modes/mode/toml";
import {elixir} from "codemirror-lang-elixir";
import {dockerFile} from "@codemirror/legacy-modes/mode/dockerfile";
import {lua} from "@codemirror/legacy-modes/mode/lua";
import {SupportedLanguage} from '../types';
import typescriptPlugin from "prettier/plugins/typescript"
@@ -43,6 +45,7 @@ import javaPrettierPlugin from "@/common/prettier/plugins/java"
import xmlPrettierPlugin from "@prettier/plugin-xml"
import * as rustPrettierPlugin from "@/common/prettier/plugins/rust";
import * as shellPrettierPlugin from "@/common/prettier/plugins/shell";
import * as dockerfilePrettierPlugin from "@/common/prettier/plugins/shell";
import tomlPrettierPlugin from "@/common/prettier/plugins/toml";
import clojurePrettierPlugin from "@cospaia/prettier-plugin-clojure";
import groovyPrettierPlugin from "@/common/prettier/plugins/groovy";
@@ -50,6 +53,7 @@ import scalaPrettierPlugin from "@/common/prettier/plugins/scala";
import clangPrettierPlugin from "@/common/prettier/plugins/clang";
import pythonPrettierPlugin from "@/common/prettier/plugins/python";
import dartPrettierPlugin from "@/common/prettier/plugins/dart";
import luaPrettierPlugin from "@/common/prettier/plugins/lua";
import * as prettierPluginEstree from "prettier/plugins/estree";
/**
@@ -60,9 +64,11 @@ export class LanguageInfo {
public token: SupportedLanguage,
public name: string,
public parser: any,
public detectIds?: string[],
public prettier?: {
parser: string;
plugins: any[];
options?: Record<string, any>; // 添加自定义配置选项
}) {
}
}
@@ -72,97 +78,105 @@ export class LanguageInfo {
*/
export const LANGUAGES: LanguageInfo[] = [
new LanguageInfo("text", "Plain Text", null),
new LanguageInfo("json", "JSON", jsonLanguage.parser, {
new LanguageInfo("json", "JSON", jsonLanguage.parser, ["json"], {
parser: "json",
plugins: [babelPrettierPlugin, prettierPluginEstree]
}),
new LanguageInfo("py", "Python", pythonLanguage.parser,{
new LanguageInfo("py", "Python", pythonLanguage.parser, ["py"], {
parser: "python",
plugins: [pythonPrettierPlugin]
}),
new LanguageInfo("html", "HTML", htmlLanguage.parser, {
new LanguageInfo("html", "HTML", htmlLanguage.parser, ["html"], {
parser: "html",
plugins: [htmlPrettierPlugin]
}),
new LanguageInfo("sql", "SQL", StandardSQL.language.parser, {
new LanguageInfo("sql", "SQL", StandardSQL.language.parser, ["sql"], {
parser: "sql",
plugins: [sqlPrettierPlugin]
}),
new LanguageInfo("md", "Markdown", markdownLanguage.parser, {
new LanguageInfo("md", "Markdown", markdownLanguage.parser, ["md"], {
parser: "markdown",
plugins: [markdownPrettierPlugin]
}),
new LanguageInfo("java", "Java", javaLanguage.parser,{
new LanguageInfo("java", "Java", javaLanguage.parser, ["java"], {
parser: "java",
plugins: [javaPrettierPlugin]
}),
new LanguageInfo("php", "PHP", phpLanguage.configure({top: "Program"}).parser, {
new LanguageInfo("php", "PHP", phpLanguage.configure({top: "Program"}).parser, ["php"], {
parser: "php",
plugins: [phpPrettierPlugin]
}),
new LanguageInfo("css", "CSS", cssLanguage.parser, {
new LanguageInfo("css", "CSS", cssLanguage.parser, ["css"], {
parser: "css",
plugins: [cssPrettierPlugin]
}),
new LanguageInfo("xml", "XML", xmlLanguage.parser,{
new LanguageInfo("xml", "XML", xmlLanguage.parser, ["xml"], {
parser: "xml",
plugins: [xmlPrettierPlugin]
}),
new LanguageInfo("cpp", "C++", cppLanguage.parser,{
new LanguageInfo("cpp", "C++", cppLanguage.parser, ["cpp", "c"], {
parser: "clang",
plugins: [clangPrettierPlugin]
}),
new LanguageInfo("rs", "Rust", rustLanguage.parser,{
new LanguageInfo("rs", "Rust", rustLanguage.parser, ["rs"], {
parser: "jinx-rust",
plugins: [rustPrettierPlugin]
}),
new LanguageInfo("cs", "C#", StreamLanguage.define(csharp).parser),
new LanguageInfo("rb", "Ruby", StreamLanguage.define(ruby).parser),
new LanguageInfo("sh", "Shell", StreamLanguage.define(shell).parser,{
new LanguageInfo("cs", "C#", StreamLanguage.define(csharp).parser, ["cs"]),
new LanguageInfo("rb", "Ruby", StreamLanguage.define(ruby).parser, ["rb"]),
new LanguageInfo("sh", "Shell", StreamLanguage.define(shell).parser, ["sh", "bat"], {
parser: "sh",
plugins: [shellPrettierPlugin]
}),
new LanguageInfo("yaml", "YAML", yamlLanguage.parser, {
new LanguageInfo("yaml", "YAML", yamlLanguage.parser, ["yaml"], {
parser: "yaml",
plugins: [yamlPrettierPlugin]
}),
new LanguageInfo("toml", "TOML", StreamLanguage.define(toml).parser,{
new LanguageInfo("toml", "TOML", StreamLanguage.define(toml).parser, ["toml"], {
parser: "toml",
plugins: [tomlPrettierPlugin]
}),
new LanguageInfo("go", "Go", StreamLanguage.define(go).parser, {
new LanguageInfo("go", "Go", StreamLanguage.define(go).parser, ["go"], {
parser: "go-format",
plugins: [goPrettierPlugin]
}),
new LanguageInfo("clj", "Clojure", StreamLanguage.define(clojure).parser,{
new LanguageInfo("clj", "Clojure", StreamLanguage.define(clojure).parser, ["clj"], {
parser: "clojure",
plugins: [clojurePrettierPlugin]
}),
new LanguageInfo("ex", "Elixir", elixir().language.parser),
new LanguageInfo("erl", "Erlang", StreamLanguage.define(erlang).parser),
new LanguageInfo("js", "JavaScript", javascriptLanguage.parser, {
new LanguageInfo("ex", "Elixir", elixir().language.parser, ["ex"]),
new LanguageInfo("erl", "Erlang", StreamLanguage.define(erlang).parser, ["erl"]),
new LanguageInfo("js", "JavaScript", javascriptLanguage.parser, ["js"], {
parser: "babel",
plugins: [babelPrettierPlugin, prettierPluginEstree]
}),
new LanguageInfo("ts", "TypeScript", typescriptLanguage.parser, {
new LanguageInfo("ts", "TypeScript", typescriptLanguage.parser, ["ts", "js"], {
parser: "typescript",
plugins: [typescriptPlugin, prettierPluginEstree]
}),
new LanguageInfo("swift", "Swift", StreamLanguage.define(swift).parser),
new LanguageInfo("kt", "Kotlin", StreamLanguage.define(kotlin).parser),
new LanguageInfo("groovy", "Groovy", StreamLanguage.define(groovy).parser,{
new LanguageInfo("swift", "Swift", StreamLanguage.define(swift).parser, ["swift"]),
new LanguageInfo("kt", "Kotlin", StreamLanguage.define(kotlin).parser, ["kt"]),
new LanguageInfo("groovy", "Groovy", StreamLanguage.define(groovy).parser, ["groovy"], {
parser: "groovy",
plugins: [groovyPrettierPlugin]
}),
new LanguageInfo("ps1", "PowerShell", StreamLanguage.define(powerShell).parser),
new LanguageInfo("dart", "Dart", null,{
new LanguageInfo("ps1", "PowerShell", StreamLanguage.define(powerShell).parser, ["ps1"]),
new LanguageInfo("dart", "Dart", null, ["dart"], {
parser: "dart",
plugins: [dartPrettierPlugin]
}),
new LanguageInfo("scala", "Scala", StreamLanguage.define(scala).parser,{
new LanguageInfo("scala", "Scala", StreamLanguage.define(scala).parser, ["scala"], {
parser: "scala",
plugins: [scalaPrettierPlugin]
}),
new LanguageInfo("dockerfile", "Dockerfile", StreamLanguage.define(dockerFile).parser, ["dockerfile"], {
parser: "dockerfile",
plugins: [dockerfilePrettierPlugin]
}),
new LanguageInfo("lua", "Lua", StreamLanguage.define(lua).parser, ["lua"], {
parser: "lua",
plugins: [luaPrettierPlugin]
}),
];
/**
@@ -180,8 +194,8 @@ export function getLanguage(token: SupportedLanguage): LanguageInfo | undefined
}
/**
* 获取所有语言的 token 列表
* 获取完整的支持语言列表(包括 'auto'
*/
export function getLanguageTokens(): SupportedLanguage[] {
return LANGUAGES.map(lang => lang.token);
export function getAllSupportedLanguages(): SupportedLanguage[] {
return ['auto', ...LANGUAGES.map(lang => lang.token)];
}

View File

@@ -5,7 +5,7 @@
import { EditorSelection, SelectionRange } from "@codemirror/state";
import { blockState } from "./state";
import { SUPPORTED_LANGUAGES } from "./types";
import { LANGUAGES } from "./lang-parser/languages";
interface LineBlock {
from: number;
@@ -14,7 +14,7 @@ interface LineBlock {
}
// 创建语言标记的正则表达式
const languageTokensMatcher = SUPPORTED_LANGUAGES.join("|");
const languageTokensMatcher = LANGUAGES.map(lang => lang.token).join("|");
const tokenRegEx = new RegExp(`^∞∞∞(${languageTokensMatcher})(-a)?$`, "g");
/**

View File

@@ -6,17 +6,14 @@ import { EditorState } from '@codemirror/state';
import { syntaxTree, syntaxTreeAvailable } from '@codemirror/language';
import { Block as BlockNode, BlockDelimiter, BlockContent, BlockLanguage, Document } from './lang-parser/parser.terms.js';
import {
CodeBlock,
SupportedLanguage,
SUPPORTED_LANGUAGES,
DELIMITER_REGEX,
DELIMITER_PREFIX,
DELIMITER_SUFFIX,
AUTO_DETECT_SUFFIX,
ParseOptions,
LanguageDetectionResult,
Block
} from './types';
import { LANGUAGES } from './lang-parser/languages';
/**
* 从语法树解析代码块
@@ -397,7 +394,7 @@ export function parseDelimiter(delimiterText: string): { language: SupportedLang
const languageName = match[1];
const isAuto = match[2] === AUTO_DETECT_SUFFIX;
const validLanguage = SUPPORTED_LANGUAGES.includes(languageName as SupportedLanguage)
const validLanguage = LANGUAGES.some(lang => lang.token === languageName)
? languageName as SupportedLanguage
: 'text';

View File

@@ -2,136 +2,102 @@
* Block 结构
*/
export interface Block {
language: {
name: string;
auto: boolean;
};
content: {
from: number;
to: number;
};
delimiter: {
from: number;
to: number;
};
range: {
from: number;
to: number;
};
language: {
name: string;
auto: boolean;
};
content: {
from: number;
to: number;
};
delimiter: {
from: number;
to: number;
};
range: {
from: number;
to: number;
};
}
/**
* 支持的语言类型
*/
export type SupportedLanguage =
| 'auto' // 自动检测
| 'text'
| 'json'
| 'py' // Python
| 'html'
| 'sql'
| 'md' // Markdown
| 'java'
| 'php'
| 'css'
| 'xml'
| 'cpp' // C++
| 'rs' // Rust
| 'cs' // C#
| 'rb' // Ruby
| 'sh' // Shell
| 'yaml'
| 'toml'
| 'go'
| 'clj' // Clojure
| 'ex' // Elixir
| 'erl' // Erlang
| 'js' // JavaScript
| 'ts' // TypeScript
| 'swift'
| 'kt' // Kotlin
| 'groovy'
| 'ps1' // PowerShell
| 'dart'
| 'scala';
/**
* 支持的语言列表
*/
export const SUPPORTED_LANGUAGES: SupportedLanguage[] = [
'auto',
'text',
'json',
'py',
'html',
'sql',
'md',
'java',
'php',
'css',
'xml',
'cpp',
'rs',
'cs',
'rb',
'sh',
'yaml',
'toml',
'go',
'clj',
'ex',
'erl',
'js',
'ts',
'swift',
'kt',
'groovy',
'ps1',
'dart',
'scala'
];
export type SupportedLanguage =
| 'auto' // 自动检测
| 'text'
| 'json'
| 'py' // Python
| 'html'
| 'sql'
| 'md' // Markdown
| 'java'
| 'php'
| 'css'
| 'xml'
| 'cpp' // C++
| 'rs' // Rust
| 'cs' // C#
| 'rb' // Ruby
| 'sh' // Shell
| 'yaml'
| 'toml'
| 'go'
| 'clj' // Clojure
| 'ex' // Elixir
| 'erl' // Erlang
| 'js' // JavaScript
| 'ts' // TypeScript
| 'swift'
| 'kt' // Kotlin
| 'groovy'
| 'ps1' // PowerShell
| 'dart'
| 'scala'
| 'dockerfile'
| 'lua'
/**
* 创建块的选项
*/
export interface CreateBlockOptions {
language?: SupportedLanguage;
auto?: boolean;
content?: string;
language?: SupportedLanguage;
auto?: boolean;
content?: string;
}
/**
* 编辑器配置选项
*/
export interface EditorOptions {
defaultBlockToken: string;
defaultBlockAutoDetect: boolean;
defaultBlockToken: string;
defaultBlockAutoDetect: boolean;
}
// 语言信息接口
export interface LanguageInfo {
name: SupportedLanguage;
auto: boolean; // 是否自动检测语言
name: SupportedLanguage;
auto: boolean; // 是否自动检测语言
}
// 位置范围接口
export interface Range {
from: number;
to: number;
from: number;
to: number;
}
// 代码块核心接口
export interface CodeBlock {
language: LanguageInfo;
content: Range; // 内容区域
delimiter: Range; // 分隔符区域
range: Range; // 整个块区域(包括分隔符和内容)
language: LanguageInfo;
content: Range; // 内容区域
delimiter: Range; // 分隔符区域
range: Range; // 整个块区域(包括分隔符和内容)
}
// 代码块解析选项
export interface ParseOptions {
fallbackLanguage?: SupportedLanguage;
enableAutoDetection?: boolean;
fallbackLanguage?: SupportedLanguage;
enableAutoDetection?: boolean;
}
// 分隔符格式常量
@@ -141,23 +107,23 @@ export const DELIMITER_SUFFIX = '\n';
export const AUTO_DETECT_SUFFIX = '-a';
// 代码块操作类型
export type BlockOperation =
| 'insert-after'
| 'insert-before'
| 'delete'
| 'move-up'
| 'move-down'
| 'change-language';
export type BlockOperation =
| 'insert-after'
| 'insert-before'
| 'delete'
| 'move-up'
| 'move-down'
| 'change-language';
// 代码块状态更新事件
export interface BlockStateUpdate {
blocks: CodeBlock[];
activeBlockIndex: number;
operation?: BlockOperation;
blocks: CodeBlock[];
activeBlockIndex: number;
operation?: BlockOperation;
}
// 语言检测结果
export interface LanguageDetectionResult {
language: SupportedLanguage;
confidence: number;
language: SupportedLanguage;
confidence: number;
}