mirror of
				https://github.com/9001/copyparty.git
				synced 2025-11-03 21:43:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
diff --git a/src/Lexer.js b/src/Lexer.js
 | 
						|
adds linetracking to marked.js v1.0.0 +git;
 | 
						|
add data-ln="%d" to most tags, %d is the source markdown line
 | 
						|
--- a/src/Lexer.js
 | 
						|
+++ b/src/Lexer.js
 | 
						|
@@ -49,4 +49,5 @@ function mangle(text) {
 | 
						|
 module.exports = class Lexer {
 | 
						|
   constructor(options) {
 | 
						|
+    this.ln = 1;  // like most editors, start couting from 1
 | 
						|
     this.tokens = [];
 | 
						|
     this.tokens.links = Object.create(null);
 | 
						|
@@ -108,4 +109,15 @@ module.exports = class Lexer {
 | 
						|
   }
 | 
						|
 
 | 
						|
+  set_ln(token, ln = this.ln) {
 | 
						|
+    // assigns ln (the current line numer) to the token,
 | 
						|
+    // then bump this.ln by the number of newlines in the contents
 | 
						|
+    //
 | 
						|
+    // if ln is set, also assigns the line counter to a new value
 | 
						|
+    // (usually a backup value from before a call into a subparser
 | 
						|
+    //  which bumped the linecounter by a subset of the newlines)
 | 
						|
+    token.ln = ln;
 | 
						|
+    this.ln = ln + (token.raw.match(/\n/g) || []).length;
 | 
						|
+  }
 | 
						|
+
 | 
						|
   /**
 | 
						|
    * Lexing
 | 
						|
@@ -113,10 +125,15 @@ module.exports = class Lexer {
 | 
						|
   blockTokens(src, tokens = [], top = true) {
 | 
						|
     src = src.replace(/^ +$/gm, '');
 | 
						|
-    let token, i, l, lastToken;
 | 
						|
+    let token, i, l, lastToken, ln;
 | 
						|
 
 | 
						|
     while (src) {
 | 
						|
+      // this.ln will be bumped by recursive calls into this func;
 | 
						|
+      // reset the count and rely on the outermost token's raw only
 | 
						|
+      ln = this.ln;
 | 
						|
+      
 | 
						|
       // newline
 | 
						|
       if (token = this.tokenizer.space(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token); // is \n if not type
 | 
						|
         if (token.type) {
 | 
						|
           tokens.push(token);
 | 
						|
@@ -128,4 +145,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.code(src, tokens)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         if (token.type) {
 | 
						|
           tokens.push(token);
 | 
						|
@@ -141,4 +159,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.fences(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -148,4 +167,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.heading(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -155,4 +175,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.nptable(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -162,4 +183,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.hr(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -170,4 +192,7 @@ module.exports = class Lexer {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
         token.tokens = this.blockTokens(token.text, [], top);
 | 
						|
+        // recursive call to blockTokens probably bumped this.ln,
 | 
						|
+        // token.raw is more reliable so reset this.ln and use that
 | 
						|
+        this.set_ln(token, ln);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -180,5 +205,9 @@ module.exports = class Lexer {
 | 
						|
         for (i = 0; i < l; i++) {
 | 
						|
           token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
 | 
						|
+          // list entries don't bump the linecounter, so let's
 | 
						|
+          this.ln++;
 | 
						|
         }
 | 
						|
+        // then reset like blockquote
 | 
						|
+        this.set_ln(token, ln);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -188,4 +217,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.html(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -195,4 +225,5 @@ module.exports = class Lexer {
 | 
						|
       if (top && (token = this.tokenizer.def(src))) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         if (!this.tokens.links[token.tag]) {
 | 
						|
           this.tokens.links[token.tag] = {
 | 
						|
@@ -207,4 +238,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.table(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -214,4 +246,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.lheading(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -221,4 +254,5 @@ module.exports = class Lexer {
 | 
						|
       if (top && (token = this.tokenizer.paragraph(src))) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
@@ -228,4 +262,5 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.text(src, tokens)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        this.set_ln(token);
 | 
						|
         if (token.type) {
 | 
						|
           tokens.push(token);
 | 
						|
@@ -263,4 +298,7 @@ module.exports = class Lexer {
 | 
						|
     for (i = 0; i < l; i++) {
 | 
						|
       token = tokens[i];
 | 
						|
+      // this.ln is at EOF when inline() is invoked;
 | 
						|
+      // all this affects <br> tags only so no biggie if it breaks
 | 
						|
+      this.ln = token.ln || this.ln;
 | 
						|
       switch (token.type) {
 | 
						|
         case 'paragraph':
 | 
						|
@@ -386,4 +424,6 @@ module.exports = class Lexer {
 | 
						|
       if (token = this.tokenizer.br(src)) {
 | 
						|
         src = src.substring(token.raw.length);
 | 
						|
+        // no need to reset (no more blockTokens anyways)
 | 
						|
+        token.ln = this.ln++;
 | 
						|
         tokens.push(token);
 | 
						|
         continue;
 | 
						|
diff --git a/src/Parser.js b/src/Parser.js
 | 
						|
--- a/src/Parser.js
 | 
						|
+++ b/src/Parser.js
 | 
						|
@@ -18,4 +18,5 @@ module.exports = class Parser {
 | 
						|
     this.textRenderer = new TextRenderer();
 | 
						|
     this.slugger = new Slugger();
 | 
						|
+    this.ln = 0; // error indicator; should always be set >=1 from tokens
 | 
						|
   }
 | 
						|
 
 | 
						|
@@ -55,4 +56,9 @@ module.exports = class Parser {
 | 
						|
     for (i = 0; i < l; i++) {
 | 
						|
       token = tokens[i];
 | 
						|
+      // take line-numbers from tokens whenever possible
 | 
						|
+      // and update the renderer's html attribute with the new value
 | 
						|
+      this.ln = token.ln || this.ln;
 | 
						|
+      this.renderer.tag_ln(this.ln);
 | 
						|
+
 | 
						|
       switch (token.type) {
 | 
						|
         case 'space': {
 | 
						|
@@ -105,7 +111,10 @@ module.exports = class Parser {
 | 
						|
             }
 | 
						|
 
 | 
						|
-            body += this.renderer.tablerow(cell);
 | 
						|
+            // the +2 is to skip the table header
 | 
						|
+            body += this.renderer.tag_ln(token.ln + j + 2).tablerow(cell);
 | 
						|
           }
 | 
						|
-          out += this.renderer.table(header, body);
 | 
						|
+          // the html attribute is now at the end of the table,
 | 
						|
+          // reset it before writing the <table> tag now
 | 
						|
+          out += this.renderer.tag_ln(token.ln).table(header, body);
 | 
						|
           continue;
 | 
						|
         }
 | 
						|
@@ -148,8 +157,12 @@ module.exports = class Parser {
 | 
						|
 
 | 
						|
             itemBody += this.parse(item.tokens, loose);
 | 
						|
-            body += this.renderer.listitem(itemBody, task, checked);
 | 
						|
+            // similar to tables, writing contents before the <ul> tag
 | 
						|
+            // so update the tag attribute as we go
 | 
						|
+            // (assuming all list entries got tagged with a source-line, probably safe w)
 | 
						|
+            body += this.renderer.tag_ln((item.tokens[0] || token).ln).listitem(itemBody, task, checked);
 | 
						|
           }
 | 
						|
 
 | 
						|
-          out += this.renderer.list(body, ordered, start);
 | 
						|
+          // then reset to the <ul>'s correct line number and write it
 | 
						|
+          out += this.renderer.tag_ln(token.ln).list(body, ordered, start);
 | 
						|
           continue;
 | 
						|
         }
 | 
						|
@@ -160,5 +173,6 @@ module.exports = class Parser {
 | 
						|
         }
 | 
						|
         case 'paragraph': {
 | 
						|
-          out += this.renderer.paragraph(this.parseInline(token.tokens));
 | 
						|
+          let t = this.parseInline(token.tokens);
 | 
						|
+          out += this.renderer.tag_ln(token.ln).paragraph(t);
 | 
						|
           continue;
 | 
						|
         }
 | 
						|
@@ -199,4 +213,6 @@ module.exports = class Parser {
 | 
						|
     for (i = 0; i < l; i++) {
 | 
						|
       token = tokens[i];
 | 
						|
+      // another thing that only affects <br/> and other inlines
 | 
						|
+      this.ln = token.ln || this.ln;
 | 
						|
       switch (token.type) {
 | 
						|
         case 'escape': {
 | 
						|
@@ -229,5 +245,7 @@ module.exports = class Parser {
 | 
						|
         }
 | 
						|
         case 'br': {
 | 
						|
-          out += renderer.br();
 | 
						|
+          // update the html attribute before writing each <br/>,
 | 
						|
+          // don't care about the others
 | 
						|
+          out += renderer.tag_ln(this.ln).br();
 | 
						|
           break;
 | 
						|
         }
 | 
						|
diff --git a/src/Renderer.js b/src/Renderer.js
 | 
						|
--- a/src/Renderer.js
 | 
						|
+++ b/src/Renderer.js
 | 
						|
@@ -11,6 +11,12 @@ module.exports = class Renderer {
 | 
						|
   constructor(options) {
 | 
						|
     this.options = options || defaults;
 | 
						|
+    this.ln = "";
 | 
						|
   }
 | 
						|
 
 | 
						|
+  tag_ln(n) {
 | 
						|
+    this.ln = ' data-ln="' + n + '"';
 | 
						|
+    return this;
 | 
						|
+  };
 | 
						|
+  
 | 
						|
   code(code, infostring, escaped) {
 | 
						|
     const lang = (infostring || '').match(/\S*/)[0];
 | 
						|
@@ -24,10 +30,10 @@ module.exports = class Renderer {
 | 
						|
 
 | 
						|
     if (!lang) {
 | 
						|
-      return '<pre><code>'
 | 
						|
+      return '<pre' + this.ln + '><code>'
 | 
						|
         + (escaped ? code : escape(code, true))
 | 
						|
         + '</code></pre>';
 | 
						|
     }
 | 
						|
 
 | 
						|
-    return '<pre><code class="'
 | 
						|
+    return '<pre' + this.ln + '><code class="'
 | 
						|
       + this.options.langPrefix
 | 
						|
       + escape(lang, true)
 | 
						|
@@ -38,5 +44,5 @@ module.exports = class Renderer {
 | 
						|
 
 | 
						|
   blockquote(quote) {
 | 
						|
-    return '<blockquote>\n' + quote + '</blockquote>\n';
 | 
						|
+    return '<blockquote' + this.ln + '>\n' + quote + '</blockquote>\n';
 | 
						|
   }
 | 
						|
 
 | 
						|
@@ -49,4 +55,5 @@ module.exports = class Renderer {
 | 
						|
       return '<h'
 | 
						|
         + level
 | 
						|
+        + this.ln
 | 
						|
         + ' id="'
 | 
						|
         + this.options.headerPrefix
 | 
						|
@@ -59,5 +66,5 @@ module.exports = class Renderer {
 | 
						|
     }
 | 
						|
     // ignore IDs
 | 
						|
-    return '<h' + level + '>' + text + '</h' + level + '>\n';
 | 
						|
+    return '<h' + level + this.ln + '>' + text + '</h' + level + '>\n';
 | 
						|
   }
 | 
						|
 
 | 
						|
@@ -73,5 +80,5 @@ module.exports = class Renderer {
 | 
						|
 
 | 
						|
   listitem(text) {
 | 
						|
-    return '<li>' + text + '</li>\n';
 | 
						|
+    return '<li' + this.ln + '>' + text + '</li>\n';
 | 
						|
   }
 | 
						|
 
 | 
						|
@@ -85,5 +92,5 @@ module.exports = class Renderer {
 | 
						|
 
 | 
						|
   paragraph(text) {
 | 
						|
-    return '<p>' + text + '</p>\n';
 | 
						|
+    return '<p' + this.ln + '>' + text + '</p>\n';
 | 
						|
   }
 | 
						|
 
 | 
						|
@@ -100,5 +107,5 @@ module.exports = class Renderer {
 | 
						|
 
 | 
						|
   tablerow(content) {
 | 
						|
-    return '<tr>\n' + content + '</tr>\n';
 | 
						|
+    return '<tr' + this.ln + '>\n' + content + '</tr>\n';
 | 
						|
   }
 | 
						|
 
 | 
						|
@@ -125,5 +132,5 @@ module.exports = class Renderer {
 | 
						|
 
 | 
						|
   br() {
 | 
						|
-    return this.options.xhtml ? '<br/>' : '<br>';
 | 
						|
+    return this.options.xhtml ? '<br' + this.ln + '/>' : '<br' + this.ln + '>';
 | 
						|
   }
 | 
						|
 
 | 
						|
@@ -151,5 +158,5 @@ module.exports = class Renderer {
 | 
						|
     }
 | 
						|
 
 | 
						|
-    let out = '<img src="' + href + '" alt="' + text + '"';
 | 
						|
+    let out = '<img' + this.ln + ' src="' + href + '" alt="' + text + '"';
 | 
						|
     if (title) {
 | 
						|
       out += ' title="' + title + '"';
 |