feat: coloration syntaxique dans le viewer de code
FlowDeck CI / test (push) Failing after 4s
FlowDeck CI / docker (push) Has been skipped

highlightCode() applique une coloration par regex côté client:
- Commentaires: # (Python/Bash), // (JS/Go/Rust/Java/SQL), /* */, <!-- -->
- Strings: "double", 'simple',
- Nombres: entiers et décimaux
- Mots-clés par langage (Python, JS/TS, Go, Rust, Java, SQL, Bash, PS)
- Décorateurs Python (@decorator)
- Appliqué ligne par ligne dans le viewer
- Couleurs: hl-kw=#ff7b72, hl-str=#a5d6ff, hl-cmt=#8b949e, hl-num=#79c0ff, hl-fn=#d2a8ff
This commit is contained in:
2026-07-11 14:15:28 -04:00
parent 335120c200
commit df44285df6
+41 -2
View File
@@ -993,17 +993,56 @@ var codeEl=document.getElementById("code-content");
var lineEl=document.getElementById("line-numbers");
fetch("{file_url}").then(function(r){{return r.text()}}).then(function(t){{
var lines=t.split("\\n");
// Remove trailing empty line
if(lines.length>1&&lines[lines.length-1]==="")lines.pop();
var numHtml="",codeHtml="";
for(var i=0;i<lines.length;i++){{
numHtml+="<span>"+(i+1)+"</span>";
codeHtml+="<span>"+escHtml(lines[i])+"</span>";
codeHtml+="<span>"+highlightCode(lines[i])+"</span>";
}}
lineEl.innerHTML=numHtml;
codeEl.innerHTML=codeHtml;
}}).catch(function(e){{codeEl.textContent="Error loading file: "+e;}});
function escHtml(s){{return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");}}
function highlightCode(line){{
var s=escHtml(line);
var lang="{lang}";
// Comments
if(lang==="python"||lang==="bash"||lang==="yaml"||lang==="toml"||lang==="powershell"){{
s=s.replace(/^(\\s*#.*)$/gm,'<span class="hl-cmt">$1</span>');
}}else if(lang==="javascript"||lang==="typescript"||lang==="go"||lang==="rust"||lang==="java"||lang==="sql"){{
s=s.replace(/^(\\s*\\/\\/.*)$/gm,'<span class="hl-cmt">$1</span>');
s=s.replace(/(\\/\\*[\\s\\S]*?\\*\\/)/g,'<span class="hl-cmt">$1</span>');
}}else if(lang==="html"||lang==="xml"){{
s=s.replace(/(&lt;!--[\\s\\S]*?--&gt;)/g,'<span class="hl-cmt">$1</span>');
}}else if(lang==="css"){{
s=s.replace(/(\\/\\*[\\s\\S]*?\\*\\/)/g,'<span class="hl-cmt">$1</span>');
}}
// Strings
s=s.replace(/(&quot;(?:[^&]|&(?!quot;))*&quot;)/g,'<span class="hl-str">$1</span>');
s=s.replace(/(&#x27;(?:[^&]|&(?!#x27;))*&#x27;)/g,'<span class="hl-str">$1</span>');
s=s.replace(/(`[^`]*`)/g,'<span class="hl-str">$1</span>');
// Numbers
s=s.replace(/\\b(\\d+\\.?\\d*)\\b/g,'<span class="hl-num">$1</span>');
// Keywords
var kw=[];
if(lang==="python")kw=["def","class","import","from","return","if","elif","else","for","while","try","except","finally","with","as","yield","raise","pass","break","continue","and","or","not","in","is","None","True","False","lambda","async","await","self"];
else if(lang==="javascript"||lang==="typescript")kw=["function","const","let","var","return","if","else","for","while","do","switch","case","break","continue","try","catch","finally","throw","new","class","extends","import","export","default","from","async","await","typeof","instanceof","this","super","null","undefined","true","false","of","in"];
else if(lang==="go")kw=["func","package","import","return","if","else","for","range","switch","case","break","continue","defer","go","chan","map","struct","interface","type","var","const","nil","true","false"];
else if(lang==="rust")kw=["fn","let","mut","const","struct","enum","impl","trait","pub","use","mod","match","if","else","for","while","loop","return","break","continue","self","super","where","as","in","ref","move","true","false","async","await"];
else if(lang==="java")kw=["public","private","protected","class","interface","extends","implements","static","final","void","int","long","double","boolean","char","String","new","return","if","else","for","while","switch","case","break","continue","try","catch","finally","throw","throws","import","package","this","super","null","true","false"];
else if(lang==="sql")kw=["SELECT","FROM","WHERE","INSERT","UPDATE","DELETE","CREATE","ALTER","DROP","TABLE","INDEX","VIEW","INTO","VALUES","SET","JOIN","LEFT","RIGHT","INNER","OUTER","ON","AND","OR","NOT","NULL","AS","ORDER","BY","GROUP","HAVING","LIMIT","OFFSET","UNION","ALL","DISTINCT","COUNT","SUM","AVG","MAX","MIN","EXISTS","BETWEEN","LIKE","IN","CASE","WHEN","THEN","ELSE","END","PRIMARY","KEY","FOREIGN","REFERENCES","CONSTRAINT","DEFAULT","CHECK","UNIQUE","CASCADE"];
else if(lang==="bash")kw=["if","then","else","elif","fi","for","while","do","done","case","esac","function","return","exit","export","local","readonly","unset","echo","printf","source","exec","trap"];
else if(lang==="powershell")kw=["function","param","if","else","elseif","foreach","for","while","do","until","switch","case","break","continue","return","throw","try","catch","finally","trap","begin","process","end","param","Write-Host","Write-Output","Get-Content","Set-Content","Out-File"];
if(kw.length>0){{
var re=new RegExp("\\\\b("+kw.join("|")+")\\\\b","g");
s=s.replace(re,'<span class="hl-kw">$1</span>');
}}
// Decorators (Python) & function calls
if(lang==="python"){{
s=s.replace(/(@\\w+)/g,'<span class="hl-fn">$1</span>');
}}
return s;
}}
function copyCode(){{
var text=Array.from(codeEl.children).map(function(s){{return s.textContent}}).join("\\n");
navigator.clipboard.writeText(text).then(function(){{