mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
typeahead: Replace code block language hint text with more clear options
This commit - Replace the blank option with an italicized option that's the current default language, if there is one selected with "default" label. - Make the "text" option more informative by adding (no highlighting) to the label. - Remove the hint for "text". - Prioritize as left to right, before start typing: blank/default language, text, quote, spoiler, math, everything else... fixes: #33682
This commit is contained in:
@@ -6,6 +6,7 @@ from pygments.lexers import get_all_lexers
|
|||||||
|
|
||||||
ZULIP_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
|
ZULIP_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
|
||||||
# The current priorities data set is based on StackOverflow's 2020 survey.
|
# The current priorities data set is based on StackOverflow's 2020 survey.
|
||||||
|
# We also prioritize text, quote, math, spoiler over others to enhance UX.
|
||||||
DATA_PATH = os.path.join(ZULIP_PATH, "tools", "setup", "lang.json")
|
DATA_PATH = os.path.join(ZULIP_PATH, "tools", "setup", "lang.json")
|
||||||
OUT_PATH = os.path.join(ZULIP_PATH, "web", "generated", "pygments_data.json")
|
OUT_PATH = os.path.join(ZULIP_PATH, "web", "generated", "pygments_data.json")
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"default": {
|
"default": {
|
||||||
|
"text": 31,
|
||||||
"javascript": 27,
|
"javascript": 27,
|
||||||
"python": 26,
|
"python": 26,
|
||||||
"java": 25,
|
"java": 25,
|
||||||
@@ -30,9 +31,9 @@
|
|||||||
},
|
},
|
||||||
"custom": {
|
"custom": {
|
||||||
"latex": 10,
|
"latex": 10,
|
||||||
"math": 5,
|
"math": 28,
|
||||||
"quote": 5,
|
"quote": 30,
|
||||||
"spoiler": 5
|
"spoiler": 29
|
||||||
},
|
},
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"js": 27,
|
"js": 27,
|
||||||
|
@@ -843,11 +843,12 @@ export function get_candidates(
|
|||||||
}
|
}
|
||||||
completing = "syntax";
|
completing = "syntax";
|
||||||
token = current_token;
|
token = current_token;
|
||||||
// If the code formatting button was triggered, we want to show a blank option
|
|
||||||
// to improve the discoverability of the possibility of specifying a language.
|
const default_language = realm.realm_default_code_block_language;
|
||||||
const language_list = compose_ui.code_formatting_button_triggered
|
const language_list = realm_playground.get_pygments_typeahead_list_for_composebox();
|
||||||
? ["", ...realm_playground.get_pygments_typeahead_list_for_composebox()]
|
if (default_language) {
|
||||||
: realm_playground.get_pygments_typeahead_list_for_composebox();
|
language_list.unshift(default_language);
|
||||||
|
}
|
||||||
compose_ui.set_code_formatting_button_triggered(false);
|
compose_ui.set_code_formatting_button_triggered(false);
|
||||||
const matcher = get_language_matcher(token);
|
const matcher = get_language_matcher(token);
|
||||||
const matches = language_list.filter((item) => matcher(item));
|
const matches = language_list.filter((item) => matcher(item));
|
||||||
@@ -1109,7 +1110,12 @@ export function content_highlighter_html(item: TypeaheadSuggestion): string | un
|
|||||||
case "stream":
|
case "stream":
|
||||||
return typeahead_helper.render_stream(item);
|
return typeahead_helper.render_stream(item);
|
||||||
case "syntax":
|
case "syntax":
|
||||||
return typeahead_helper.render_typeahead_item({primary: item.language});
|
return typeahead_helper.render_typeahead_item({
|
||||||
|
primary: item.language,
|
||||||
|
is_default_language:
|
||||||
|
item.language !== "" &&
|
||||||
|
item.language === realm.realm_default_code_block_language,
|
||||||
|
});
|
||||||
case "topic_jump":
|
case "topic_jump":
|
||||||
return typeahead_helper.render_typeahead_item({primary: item.message});
|
return typeahead_helper.render_typeahead_item({primary: item.message});
|
||||||
case "topic_list": {
|
case "topic_list": {
|
||||||
@@ -1415,15 +1421,6 @@ function get_footer_html(): string | false {
|
|||||||
case "silent_mention":
|
case "silent_mention":
|
||||||
tip_text = $t({defaultMessage: "This silent mention won't trigger notifications."});
|
tip_text = $t({defaultMessage: "This silent mention won't trigger notifications."});
|
||||||
break;
|
break;
|
||||||
case "syntax":
|
|
||||||
if (realm.realm_default_code_block_language !== "") {
|
|
||||||
tip_text = $t(
|
|
||||||
{defaultMessage: "Default is {language}. Use 'text' to disable highlighting."},
|
|
||||||
{language: realm.realm_default_code_block_language},
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1465,6 +1462,15 @@ export function initialize_compose_typeahead($element: JQuery<HTMLTextAreaElemen
|
|||||||
if (item.is_new_topic) {
|
if (item.is_new_topic) {
|
||||||
return `<em>${$t({defaultMessage: "New"})}</em>`;
|
return `<em>${$t({defaultMessage: "New"})}</em>`;
|
||||||
}
|
}
|
||||||
|
} else if (item.type === "syntax") {
|
||||||
|
if (
|
||||||
|
item.language !== "" &&
|
||||||
|
item.language === realm.realm_default_code_block_language
|
||||||
|
) {
|
||||||
|
return `<em>${$t({defaultMessage: "(default)"})}</em>`;
|
||||||
|
} else if (item.language === "text") {
|
||||||
|
return `<em>${$t({defaultMessage: "(no highlighting)"})}</em>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
@@ -113,6 +113,7 @@ export let render_typeahead_item = (args: {
|
|||||||
topic_object?: TopicSuggestion;
|
topic_object?: TopicSuggestion;
|
||||||
is_stream_topic?: boolean;
|
is_stream_topic?: boolean;
|
||||||
is_empty_string_topic?: boolean;
|
is_empty_string_topic?: boolean;
|
||||||
|
is_default_language?: boolean;
|
||||||
}): string => {
|
}): string => {
|
||||||
const has_image = args.img_src !== undefined;
|
const has_image = args.img_src !== undefined;
|
||||||
const has_status = args.status_emoji_info !== undefined;
|
const has_status = args.status_emoji_info !== undefined;
|
||||||
@@ -434,8 +435,15 @@ function retain_unique_language_aliases(matches: string[]): string[] {
|
|||||||
|
|
||||||
export function sort_languages(matches: LanguageSuggestion[], query: string): LanguageSuggestion[] {
|
export function sort_languages(matches: LanguageSuggestion[], query: string): LanguageSuggestion[] {
|
||||||
const languages = matches.map((object) => object.language);
|
const languages = matches.map((object) => object.language);
|
||||||
|
const default_language = realm.realm_default_code_block_language;
|
||||||
const results = typeahead.triage(query, languages, (x) => x, compare_language);
|
const results = typeahead.triage(query, languages, (x) => x, compare_language);
|
||||||
const unique_languages = retain_unique_language_aliases([...results.matches, ...results.rest]);
|
let language_results;
|
||||||
|
if (default_language && results.matches.includes(default_language)) {
|
||||||
|
language_results = [default_language, ...results.matches, ...results.rest];
|
||||||
|
} else {
|
||||||
|
language_results = [...results.matches, ...results.rest];
|
||||||
|
}
|
||||||
|
const unique_languages = retain_unique_language_aliases(language_results);
|
||||||
return unique_languages.map((language) => ({
|
return unique_languages.map((language) => ({
|
||||||
language,
|
language,
|
||||||
type: "syntax",
|
type: "syntax",
|
||||||
|
@@ -2349,6 +2349,7 @@ body:not(.spectator-view) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.default-language-display,
|
||||||
.empty-topic-display,
|
.empty-topic-display,
|
||||||
.empty-topic-placeholder-display::placeholder {
|
.empty-topic-placeholder-display::placeholder {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
{{!-- Separate container to ensure overflowing text remains in this container. --}}
|
{{!-- Separate container to ensure overflowing text remains in this container. --}}
|
||||||
<div class="typeahead-text-container{{#if has_secondary_html}} has_secondary_html{{/if}}">
|
<div class="typeahead-text-container{{#if has_secondary_html}} has_secondary_html{{/if}}">
|
||||||
<strong class="typeahead-strong-section{{#if is_empty_string_topic}} empty-topic-display{{/if}}">
|
<strong class="typeahead-strong-section{{#if is_empty_string_topic}} empty-topic-display{{/if}}{{#if is_default_language}} default-language-display{{/if}}">
|
||||||
{{~#if stream~}}
|
{{~#if stream~}}
|
||||||
{{~> inline_decorated_channel_name stream=stream ~}}
|
{{~> inline_decorated_channel_name stream=stream ~}}
|
||||||
{{~else~}}
|
{{~else~}}
|
||||||
|
@@ -2306,7 +2306,10 @@ test("content_highlighter_html", ({override_rewire}) => {
|
|||||||
ct.get_or_set_completing_for_tests("syntax");
|
ct.get_or_set_completing_for_tests("syntax");
|
||||||
th_render_typeahead_item_called = false;
|
th_render_typeahead_item_called = false;
|
||||||
override_rewire(typeahead_helper, "render_typeahead_item", (item) => {
|
override_rewire(typeahead_helper, "render_typeahead_item", (item) => {
|
||||||
assert.deepEqual(item, {primary: "py"});
|
assert.deepEqual(item, {
|
||||||
|
is_default_language: false,
|
||||||
|
primary: "py",
|
||||||
|
});
|
||||||
th_render_typeahead_item_called = true;
|
th_render_typeahead_item_called = true;
|
||||||
});
|
});
|
||||||
ct.content_highlighter_html({type: "syntax", language: "py"});
|
ct.content_highlighter_html({type: "syntax", language: "py"});
|
||||||
|
@@ -78,6 +78,10 @@ run_test("get_pygments_typeahead_list_for_settings", () => {
|
|||||||
let iterator = candidates.entries();
|
let iterator = candidates.entries();
|
||||||
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: custom_lang"}));
|
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: custom_lang"}));
|
||||||
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: invent_a_lang"}));
|
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: invent_a_lang"}));
|
||||||
|
assert.equal(iterator.next().value[1], "Text only (text, text)");
|
||||||
|
assert.equal(iterator.next().value[1], "quote (quote, quote)");
|
||||||
|
assert.equal(iterator.next().value[1], "spoiler (spoiler, spoiler)");
|
||||||
|
assert.equal(iterator.next().value[1], "math (math, math)");
|
||||||
assert.equal(iterator.next().value[1], "JavaScript (javascript, js, javascript, js)");
|
assert.equal(iterator.next().value[1], "JavaScript (javascript, js, javascript, js)");
|
||||||
assert.equal(
|
assert.equal(
|
||||||
iterator.next().value[1],
|
iterator.next().value[1],
|
||||||
@@ -96,6 +100,10 @@ run_test("get_pygments_typeahead_list_for_settings", () => {
|
|||||||
);
|
);
|
||||||
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: custom_lang"}));
|
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: custom_lang"}));
|
||||||
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: invent_a_lang"}));
|
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: invent_a_lang"}));
|
||||||
|
assert.equal(iterator.next().value[1], "Text only (text, text)");
|
||||||
|
assert.equal(iterator.next().value[1], "quote (quote, quote)");
|
||||||
|
assert.equal(iterator.next().value[1], "spoiler (spoiler, spoiler)");
|
||||||
|
assert.equal(iterator.next().value[1], "math (math, math)");
|
||||||
assert.equal(iterator.next().value[1], "JavaScript (javascript, js, javascript, js)");
|
assert.equal(iterator.next().value[1], "JavaScript (javascript, js, javascript, js)");
|
||||||
assert.equal(
|
assert.equal(
|
||||||
iterator.next().value[1],
|
iterator.next().value[1],
|
||||||
@@ -107,9 +115,7 @@ run_test("get_pygments_typeahead_list_for_settings", () => {
|
|||||||
iterator = candidates.entries();
|
iterator = candidates.entries();
|
||||||
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: invent_a_lang"}));
|
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: invent_a_lang"}));
|
||||||
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: custom_lang"}));
|
assert.equal(iterator.next().value[1], $t({defaultMessage: "Custom language: custom_lang"}));
|
||||||
assert.equal(iterator.next().value[1], "JavaScript (javascript, js, javascript, js)");
|
assert.equal(iterator.next().value[1], "Text only (text, text)");
|
||||||
assert.equal(
|
assert.equal(iterator.next().value[1], "quote (quote, quote)");
|
||||||
iterator.next().value[1],
|
assert.equal(iterator.next().value[1], "spoiler (spoiler, spoiler)");
|
||||||
"Python (python, bazel, py, py3, pyi, python3, sage, starlark, python, bazel, py, py3, pyi, python3, sage, starlark)",
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
@@ -394,12 +394,15 @@ test("sort_streams", ({override, override_rewire}) => {
|
|||||||
|
|
||||||
function language_items(languages) {
|
function language_items(languages) {
|
||||||
return languages.map((language) => ({
|
return languages.map((language) => ({
|
||||||
type: "syntax",
|
|
||||||
language,
|
language,
|
||||||
|
type: "syntax",
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
test("sort_languages", ({override_rewire}) => {
|
test("sort_languages", ({override, override_rewire}) => {
|
||||||
|
override(realm, "realm_default_code_block_language", "dart");
|
||||||
|
const default_language = realm.realm_default_code_block_language;
|
||||||
|
|
||||||
override_rewire(pygments_data, "langs", {
|
override_rewire(pygments_data, "langs", {
|
||||||
python: {priority: 26},
|
python: {priority: 26},
|
||||||
javascript: {priority: 27},
|
javascript: {priority: 27},
|
||||||
@@ -407,20 +410,52 @@ test("sort_languages", ({override_rewire}) => {
|
|||||||
pascal: {priority: 15},
|
pascal: {priority: 15},
|
||||||
perl: {priority: 3},
|
perl: {priority: 3},
|
||||||
css: {priority: 21},
|
css: {priority: 21},
|
||||||
|
spoiler: {priority: 29},
|
||||||
|
text: {priority: 31},
|
||||||
|
quote: {priority: 30},
|
||||||
|
math: {priority: 28},
|
||||||
});
|
});
|
||||||
|
|
||||||
let test_langs = language_items(["pascal", "perl", "php", "python", "javascript"]);
|
let test_langs = language_items(["pascal", "perl", "php", "python", "spoiler", "javascript"]);
|
||||||
test_langs = th.sort_languages(test_langs, "p");
|
test_langs = th.sort_languages(test_langs, "p");
|
||||||
|
|
||||||
// Sort languages by matching first letter, and then by popularity
|
// Sort languages by matching first letter, and then by popularity
|
||||||
assert.deepEqual(test_langs, language_items(["python", "php", "pascal", "perl", "javascript"]));
|
assert.deepEqual(
|
||||||
|
test_langs,
|
||||||
|
language_items(["python", "php", "pascal", "perl", "spoiler", "javascript"]),
|
||||||
|
);
|
||||||
|
|
||||||
// Test if popularity between two languages are the same
|
// Test if popularity between two languages are the same
|
||||||
pygments_data.langs.php = {priority: 26};
|
pygments_data.langs.php = {priority: 26};
|
||||||
test_langs = language_items(["pascal", "perl", "php", "python", "javascript"]);
|
test_langs = language_items(["pascal", "perl", "php", "python", "spoiler", "javascript"]);
|
||||||
test_langs = th.sort_languages(test_langs, "p");
|
test_langs = th.sort_languages(test_langs, "p");
|
||||||
|
|
||||||
assert.deepEqual(test_langs, language_items(["php", "python", "pascal", "perl", "javascript"]));
|
assert.deepEqual(
|
||||||
|
test_langs,
|
||||||
|
language_items(["php", "python", "pascal", "perl", "spoiler", "javascript"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
test_langs = language_items([
|
||||||
|
default_language,
|
||||||
|
"text",
|
||||||
|
"quote",
|
||||||
|
"math",
|
||||||
|
"python",
|
||||||
|
"javascript",
|
||||||
|
]);
|
||||||
|
const test_langs_for_default = th.sort_languages(test_langs, "d");
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
test_langs_for_default,
|
||||||
|
language_items([default_language, "text", "quote", "math", "javascript", "python"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
test_langs = th.sort_languages(test_langs, "t");
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
test_langs,
|
||||||
|
language_items(["text", "quote", "math", "javascript", "python", default_language]),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("sort_languages on actual data", () => {
|
test("sort_languages on actual data", () => {
|
||||||
|
Reference in New Issue
Block a user