Skip to content
Merged
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
121 changes: 72 additions & 49 deletions app/src/protyle/toolbar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1236,29 +1236,33 @@ export class Toolbar {
hideElements(["hint"], protyle);
window.siyuan.menus.menu.remove();
this.range = getEditorRange(nodeElement);
let html = `<div class="b3-list-item">${window.siyuan.languages.clear}</div>`;

this.subElement.style.width = "";
this.subElement.style.padding = "";
this.subElement.innerHTML = `<div data-id="codeLanguage" class="fn__flex-column" style="max-height:50vh">
<input placeholder="${window.siyuan.languages.search}" style="margin: 0 8px 4px 8px" class="b3-text-field"/>
<div class="b3-list fn__flex-1 b3-list--background" style="position: relative"></div>
</div>`;
const listElement = this.subElement.lastElementChild.lastElementChild as HTMLElement;

let html = `<div data-id="clearLanguage" class="b3-list-item">${window.siyuan.languages.clear}</div>`;
let hljsLanguages = Constants.ALIAS_CODE_LANGUAGES.concat(window.hljs?.listLanguages() ?? []).sort();

const eventDetail = {languages: hljsLanguages};
const eventDetail = {languages: hljsLanguages, type: "init", listElement};
if (protyle.app && protyle.app.plugins) {
protyle.app.plugins.forEach((plugin: any) => {
plugin.eventBus.emit("code-language-update", eventDetail);
});
}

hljsLanguages = eventDetail.languages;
hljsLanguages.forEach((item, index) => {
html += `<div class="b3-list-item${index === 0 ? " b3-list-item--focus" : ""}">${item}</div>`;
hljsLanguages.forEach((item) => {
html += `<div data-id="${item}" class="b3-list-item">${item}</div>`;
});

this.subElement.style.width = "";
this.subElement.style.padding = "";
this.subElement.innerHTML = `<div class="fn__flex-column" style="max-height:50vh">
<input placeholder="${window.siyuan.languages.search}" style="margin: 0 8px 4px 8px" class="b3-text-field"/>
<div class="b3-list fn__flex-1 b3-list--background" style="position: relative">${html}</div>
</div>`;
listElement.innerHTML = html;
listElement.firstElementChild.nextElementSibling.classList.add("b3-list-item--focus");

const listElement = this.subElement.lastElementChild.lastElementChild as HTMLElement;
const inputElement = this.subElement.querySelector("input");
inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
event.stopPropagation();
Expand All @@ -1269,63 +1273,82 @@ export class Toolbar {
if (event.key === "Enter") {
this.updateLanguage(languageElements, protyle, this.subElement.querySelector(".b3-list-item--focus").textContent);
event.preventDefault();
Copy link

Copilot AI Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The event.stopPropagation() call was removed from line 1276 after the Enter key handler. This could allow the event to bubble up unexpectedly. Consider whether event propagation should still be stopped here to maintain consistent behavior with the Escape key handler on line 1281.

Suggested change
event.preventDefault();
event.preventDefault();
event.stopPropagation();

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TCOTC 移除这个的原因是?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vanessa219 前面有,后面多余的就删了

Image

event.stopPropagation();
return;
}
if (event.key === "Escape") {
this.subElement.classList.add("fn__none");
focusByRange(this.range);
}
});

const highlightText = (text: string, search: string) => {
// 转义正则特殊字符
const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// 创建不区分大小写的正则表达式
const regex = new RegExp(escapedSearch, "gi");
// 替换匹配内容并保留原始大小写
Comment on lines +1285 to +1289
Copy link

Copilot AI Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The inline comments are in Chinese while the codebase appears to use English elsewhere. Consider translating these comments to English for consistency: '转义正则特殊字符' (Escape regex special characters), '创建不区分大小写的正则表达式' (Create case-insensitive regex), '替换匹配内容并保留原始大小写' (Replace matches while preserving original case).

Suggested change
// 转义正则特殊字符
const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// 创建不区分大小写的正则表达式
const regex = new RegExp(escapedSearch, "gi");
// 替换匹配内容并保留原始大小写
// Escape regex special characters
const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// Create case-insensitive regex
const regex = new RegExp(escapedSearch, "gi");
// Replace matches while preserving original case

Copilot uses AI. Check for mistakes.
return text.replace(regex, match =>
`<b>${match}</b>`
);
};

inputElement.addEventListener("input", (event) => {
const lowerCaseValue = inputElement.value.toLowerCase();
const matchLanguages = hljsLanguages.filter(item => item.includes(lowerCaseValue));
let html = "";
// sort
let matchInput = false;
if (lowerCaseValue) {
matchLanguages.sort((a, b) => {
if (a.startsWith(lowerCaseValue) && b.startsWith(lowerCaseValue)) {
if (a.length < b.length) {
return -1;
} else if (a.length === b.length) {
return 0;
} else {
return 1;
}
} else if (a.startsWith(lowerCaseValue)) {
return -1;
} else if (b.startsWith(lowerCaseValue)) {
return 1;
} else {
return 0;
}
const value = inputElement.value.trim();
let matchLanguages;
let html = `<div data-id="clearLanguage" class="b3-list-item">${window.siyuan.languages.clear}</div>`;
let isMatchLanguages = false;
// Sort
if (value) {
const lowerCaseValue = value.toLowerCase();
matchLanguages = hljsLanguages.filter(
item => item.toLowerCase().includes(lowerCaseValue)
).sort((a, b) => {
// 不区分大小写
Copy link

Copilot AI Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The inline comment '不区分大小写' is in Chinese. Consider translating to English: 'Case-insensitive comparison'.

Suggested change
// 不区分大小写
// Case-insensitive comparison

Copilot uses AI. Check for mistakes.
const aStartsWith = a.toLowerCase().startsWith(lowerCaseValue);
const bStartsWith = b.toLowerCase().startsWith(lowerCaseValue);

// 两者都匹配开头时,短字符串优先
Copy link

Copilot AI Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The inline comment '两者都匹配开头时,短字符串优先' is in Chinese. Consider translating to English: 'When both match the prefix, shorter strings take priority'.

Suggested change
// 两者都匹配开头时,短字符串优先
// When both match the prefix, shorter strings take priority

Copilot uses AI. Check for mistakes.
if (aStartsWith && bStartsWith) return a.length - b.length;
if (aStartsWith) return -1;
if (bStartsWith) return 1;

// 都不匹配时保持原顺序
Copy link

Copilot AI Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The inline comment '都不匹配时保持原顺序' is in Chinese. Consider translating to English: 'Maintain original order when neither matches'.

Suggested change
// 都不匹配时保持原顺序
// Maintain original order when neither matches

Copilot uses AI. Check for mistakes.
return 0;
});

if (window.hljs?.getLanguage(value)) {
// Default languages and their aliases
matchLanguages = [value].concat(matchLanguages.filter(item => item !== value));
}
}

const eventDetail = {languages: matchLanguages};
const eventDetail = {languages: value ? matchLanguages : hljsLanguages, type: "match", value, listElement};
if (protyle.app && protyle.app.plugins) {
protyle.app.plugins.forEach((plugin: any) => {
plugin.eventBus.emit("code-language-update", eventDetail);
});
}

matchLanguages.forEach((item) => {
if (inputElement.value === item) {
matchInput = true;
}
html += `<div class="b3-list-item">${item.replace(lowerCaseValue, "<b>" + lowerCaseValue + "</b>")}</div>`;
});
if (inputElement.value.trim() && !matchInput) {
html = `<div class="b3-list-item"><b>${escapeHtml(inputElement.value.replace(/`| /g, "_"))}</b></div>${html}`;
}
html = `<div class="b3-list-item">${window.siyuan.languages.clear}</div>` + html;
listElement.innerHTML = html;
if (listElement.childElementCount > 2 && !matchInput && inputElement.value.trim()) {
listElement.firstElementChild.nextElementSibling.nextElementSibling.classList.add("b3-list-item--focus");
matchLanguages = eventDetail.languages;
if (value) {
matchLanguages.forEach((item) => {
if (value === item) {
isMatchLanguages = true;
html += `<div data-id="${item}" class="b3-list-item"><b>${item}</b></div>`;
} else {
html += `<div data-id="${item}" class="b3-list-item">${highlightText(item, value)}</div>`;
}
});
} else {
listElement.firstElementChild.nextElementSibling.classList.add("b3-list-item--focus");
matchLanguages.forEach((item) => {
html += `<div data-id="${item}" class="b3-list-item">${item}</div>`;
});
}
if (value && !isMatchLanguages) {
html += `<div data-id="customLanguage" class="b3-list-item"><b>${escapeHtml(value.replace(/`| /g, "_"))}</b></div>`;
}
listElement.innerHTML = html;
listElement.firstElementChild.nextElementSibling.classList.add("b3-list-item--focus");
event.stopPropagation();
});
listElement.addEventListener("click", (event) => {
Expand Down