From 6c31a9948bf98e445a367ae6bd62d2c11afe3ab4 Mon Sep 17 00:00:00 2001 From: Stef Rave Date: Tue, 27 Dec 2016 16:33:43 +0100 Subject: [PATCH] Add the line numbers to the SVG diagram to enable real time tracking --- src/diagram.js | 30 ++++++++++++++++++------------ src/grammar.jison | 10 +++++----- src/theme-snap.js | 26 ++++++++++++++++---------- src/theme.js | 5 +++-- test/grammar-tests.js | 8 ++++---- 5 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/diagram.js b/src/diagram.js index e01a651..318c82f 100644 --- a/src/diagram.js +++ b/src/diagram.js @@ -13,7 +13,7 @@ function Diagram() { /* * Return an existing actor with this alias, or creates a new one with alias and name. */ -Diagram.prototype.getActor = function(alias, name) { +Diagram.prototype.getActor = function(alias, name, lineno) { alias = alias.trim(); var i; @@ -23,14 +23,14 @@ Diagram.prototype.getActor = function(alias, name) { return actors[i]; } } - i = actors.push(new Diagram.Actor(alias, (name || alias), actors.length)); + i = actors.push(new Diagram.Actor(alias, (name || alias), actors.length, lineno)); return actors[ i - 1 ]; }; /* * Parses the input as either a alias, or a "name as alias", and returns the corresponding actor. */ -Diagram.prototype.getActorWithAlias = function(input) { +Diagram.prototype.getActorWithAlias = function(input, lineno) { input = input.trim(); // We are lazy and do some of the parsing in javascript :(. TODO move into the .jison file. @@ -43,41 +43,47 @@ Diagram.prototype.getActorWithAlias = function(input) { } else { name = alias = input; } - return this.getActor(alias, name); + return this.getActor(alias, name, lineno); }; -Diagram.prototype.setTitle = function(title) { - this.title = title; +Diagram.prototype.setTitle = function(title, lineno) { + this.title = { + message: title, + lineno: lineno + }; }; Diagram.prototype.addSignal = function(signal) { this.signals.push(signal); }; -Diagram.Actor = function(alias, name, index) { - this.alias = alias; - this.name = name; - this.index = index; +Diagram.Actor = function(alias, name, index, lineno) { + this.alias = alias; + this.name = name; + this.index = index; + this.lineno = lineno; }; -Diagram.Signal = function(actorA, signaltype, actorB, message) { +Diagram.Signal = function(actorA, signaltype, actorB, message, lineno) { this.type = 'Signal'; this.actorA = actorA; this.actorB = actorB; this.linetype = signaltype & 3; this.arrowtype = (signaltype >> 2) & 3; this.message = message; + this.lineno = lineno; }; Diagram.Signal.prototype.isSelf = function() { return this.actorA.index == this.actorB.index; }; -Diagram.Note = function(actor, placement, message) { +Diagram.Note = function(actor, placement, message, lineno) { this.type = 'Note'; this.actor = actor; this.placement = placement; this.message = message; + this.lineno = lineno; if (this.hasManyActors() && actor[0] == actor[1]) { throw new Error('Note should be over two different actors'); diff --git a/src/grammar.jison b/src/grammar.jison index 9746e92..1a87261 100644 --- a/src/grammar.jison +++ b/src/grammar.jison @@ -57,12 +57,12 @@ statement : 'participant' actor_alias { $2; } | signal { yy.parser.yy.addSignal($1); } | note_statement { yy.parser.yy.addSignal($1); } - | 'title' message { yy.parser.yy.setTitle($2); } + | 'title' message { yy.parser.yy.setTitle($2, yylineno); } ; note_statement - : 'note' placement actor message { $$ = new Diagram.Note($3, $2, $4); } - | 'note' 'over' actor_pair message { $$ = new Diagram.Note($3, Diagram.PLACEMENT.OVER, $4); } + : 'note' placement actor message { $$ = new Diagram.Note($3, $2, $4, yylineno); } + | 'note' 'over' actor_pair message { $$ = new Diagram.Note($3, Diagram.PLACEMENT.OVER, $4, yylineno); } ; actor_pair @@ -77,7 +77,7 @@ placement signal : actor signaltype actor message - { $$ = new Diagram.Signal($1, $2, $3, $4); } + { $$ = new Diagram.Signal($1, $2, $3, $4, yylineno); } ; actor @@ -85,7 +85,7 @@ actor ; actor_alias - : ACTOR { $$ = yy.parser.yy.getActorWithAlias(Diagram.unescape($1)); } + : ACTOR { $$ = yy.parser.yy.getActorWithAlias(Diagram.unescape($1), yylineno); } ; signaltype diff --git a/src/theme-snap.js b/src/theme-snap.js index 4241aff..7f063be 100644 --- a/src/theme-snap.js +++ b/src/theme-snap.js @@ -155,11 +155,17 @@ if (typeof Snap != 'undefined') { }, // Finishes the group, and returns the element - finishGroup: function() { - var g = this.paper_.group.apply(this.paper_, this._stack); - this.beginGroup(); // Reset the group - return g; - }, + finishGroup: function(groupName, lineno) { + var g = this.paper_.group.apply(this.paper_, this._stack); + this.beginGroup(); + if (groupName) { + g.addClass(groupName); + } + if (lineno !== undefined) { + g.attr({'data-lineno': lineno + 1}); // +1 to correct jison line numbering + } + return g; + }, createText: function(text, font) { text = _.invoke(text.split('\n'), 'trim'); @@ -220,31 +226,31 @@ if (typeof Snap != 'undefined') { drawTitle: function() { this.beginGroup(); BaseTheme.prototype.drawTitle.call(this); - return this.finishGroup().addClass('title'); + return this.finishGroup('title', this.title_ ? this.title_.lineno : undefined); }, drawActor: function(actor, offsetY, height) { this.beginGroup(); BaseTheme.prototype.drawActor.call(this, actor, offsetY, height); - return this.finishGroup().addClass('actor'); + return this.finishGroup('actor', actor.lineno); }, drawSignal: function(signal, offsetY) { this.beginGroup(); BaseTheme.prototype.drawSignal.call(this, signal, offsetY); - return this.finishGroup().addClass('signal'); + return this.finishGroup('signal', signal.lineno); }, drawSelfSignal: function(signal, offsetY) { this.beginGroup(); BaseTheme.prototype.drawSelfSignal.call(this, signal, offsetY); - return this.finishGroup().addClass('signal'); + return this.finishGroup('signal', signal.lineno); }, drawNote: function(note, offsetY) { this.beginGroup(); BaseTheme.prototype.drawNote.call(this, note, offsetY); - return this.finishGroup().addClass('note'); + return this.finishGroup('note', note.lineno); }, }); diff --git a/src/theme.js b/src/theme.js index dd101f8..567cfc4 100644 --- a/src/theme.js +++ b/src/theme.js @@ -185,9 +185,10 @@ _.extend(BaseTheme.prototype, { // Setup some layout stuff if (diagram.title) { var title = this.title_ = {}; - var bb = this.textBBox(diagram.title, font); + title.message = diagram.title.message; + title.lineno = diagram.title.lineno; + var bb = this.textBBox(title.message, font); title.textBB = bb; - title.message = diagram.title; title.width = bb.width + (TITLE_PADDING + TITLE_MARGIN) * 2; title.height = bb.height + (TITLE_PADDING + TITLE_MARGIN) * 2; diff --git a/test/grammar-tests.js b/test/grammar-tests.js index 18a18ab..5c9b675 100644 --- a/test/grammar-tests.js +++ b/test/grammar-tests.js @@ -111,12 +111,12 @@ test('Dashed Open Arrow', function() { }); test('Titles', function() { - equal(Diagram.parse('Title: title').title, 'title', 'Title'); - equal(Diagram.parse('Title: line1\\nline2').title, 'line1\nline2', 'Multiline Title'); + deepEqual(Diagram.parse('Title: title').title, {message: 'title', lineno: 0}, 'Title'); + deepEqual(Diagram.parse('Title: line1\\nline2').title, {message: 'line1\nline2', lineno: 0}, 'Multiline Title'); }); test('Unicode', function() { - equal(Diagram.parse('Title: 中国').title, '中国', 'Unicode Title'); + deepEqual(Diagram.parse('Title: 中国').title, {message: '中国', lineno: 0}, 'Unicode Title'); assertEmptyDocument(Diagram.parse('# 中国')); assertSingleActor(Diagram.parse('Participant 中国'), '中国'); assertSingleActor(Diagram.parse('Participant 中国 as alias'), 'alias', '中国'); @@ -149,7 +149,7 @@ test('Comments', function() { assertSingleArrow(Diagram.parse('A->B: Message # not a comment'), ARROWTYPE.FILLED, LINETYPE.SOLID, 'A', 'B', 'Message # not a comment'); - equal(Diagram.parse('Title: title # not a comment').title, 'title # not a comment'); + deepEqual(Diagram.parse('Title: title # not a comment').title, {message: 'title # not a comment', lineno: 0}); assertSingleNote(Diagram.parse('note left of A: Message # not a comment'), PLACEMENT.LEFTOF, 'A', 'Message # not a comment'); });