Tidy up chunky theme, add theme name autocomplete [#17]

This commit is contained in:
David Evans 2017-11-06 21:46:40 +00:00
parent f6f557bcd7
commit 2cb34c273c
9 changed files with 119 additions and 50 deletions

View File

@ -14,7 +14,7 @@
form-action 'none'; form-action 'none';
"> ">
<title>Sequence Diagram</title> <title>Readme Image Generator</title>
<link rel="icon" href="favicon.png"> <link rel="icon" href="favicon.png">
<link rel="stylesheet" href="styles/readme_images.css"> <link rel="stylesheet" href="styles/readme_images.css">

View File

@ -109,6 +109,9 @@ define([
const code = new CodeMirror(container, { const code = new CodeMirror(container, {
value, value,
mode: 'sequence', mode: 'sequence',
globals: {
themes: this.renderer.getThemeNames(),
},
lineNumbers: true, lineNumbers: true,
showTrailingSpace: true, showTrailingSpace: true,
extraKeys: { extraKeys: {

View File

@ -24,7 +24,11 @@ defineDescribe('Interface', ['./Interface'], (Interface) => {
agents: [], agents: [],
stages: [], stages: [],
}); });
renderer = jasmine.createSpyObj('renderer', ['render', 'svg']); renderer = jasmine.createSpyObj('renderer', [
'render',
'svg',
'getThemeNames',
]);
renderer.svg.and.returnValue(document.createElement('svg')); renderer.svg.and.returnValue(document.createElement('svg'));
container = jasmine.createSpyObj('container', ['appendChild']); container = jasmine.createSpyObj('container', ['appendChild']);
exporter = jasmine.createSpyObj('exporter', ['getSVGURL']); exporter = jasmine.createSpyObj('exporter', ['getSVGURL']);

View File

@ -17,6 +17,8 @@
return o; return o;
} }
const PNG_RESOLUTION = 4;
const FAVICON_SRC = ( const FAVICON_SRC = (
'theme chunky\n' + 'theme chunky\n' +
'define ABC as A, DEF as B\n' + 'define ABC as A, DEF as B\n' +
@ -47,7 +49,7 @@
results.push({ results.push({
file: 'favicon.png', file: 'favicon.png',
code: FAVICON_SRC, code: FAVICON_SRC,
height: 64, size: {width: 16, height: 16},
}); });
return results; return results;
} }
@ -61,8 +63,6 @@
} }
} }
const PNG_RESOLUTION = 4;
/* jshint -W072 */ // Allow several required modules /* jshint -W072 */ // Allow several required modules
requirejs([ requirejs([
'sequence/Parser', 'sequence/Parser',
@ -91,7 +91,7 @@
status.appendChild(statusText); status.appendChild(statusText);
document.body.appendChild(status); document.body.appendChild(status);
function renderSample({file, code, height}) { function renderSample({file, code, size}) {
const renderer = new Renderer({themes}); const renderer = new Renderer({themes});
const exporter = new Exporter(); const exporter = new Exporter();
@ -124,11 +124,11 @@
const parsed = parser.parse(code); const parsed = parser.parse(code);
const sequence = generator.generate(parsed); const sequence = generator.generate(parsed);
renderer.render(sequence); renderer.render(sequence);
let resolution = PNG_RESOLUTION; if(size) {
if(height) { renderer.width = size.width;
resolution = height / renderer.height; renderer.height = size.height;
} }
exporter.getPNGURL(renderer, resolution, (url) => { exporter.getPNGURL(renderer, PNG_RESOLUTION, (url) => {
raster.setAttribute('src', url); raster.setAttribute('src', url);
downloadPNG.setAttribute('href', url); downloadPNG.setAttribute('href', url);
}); });

View File

@ -1,4 +1,4 @@
define(() => { define(['core/ArrayUtilities'], (array) => {
'use strict'; 'use strict';
const TRIMMER = /^([ \t]*)(.*)$/; const TRIMMER = /^([ \t]*)(.*)$/;
@ -32,6 +32,26 @@ define(() => {
}; };
} }
function getGlobals({global, prefix = '', suffix = ''}, globals) {
const identified = globals[global];
if(!identified) {
return [];
}
return identified.map((item) => (prefix + item + suffix));
}
function populateGlobals(suggestions, globals = {}) {
for(let i = 0; i < suggestions.length;) {
if(typeof suggestions[i] === 'object') {
const identified = getGlobals(suggestions[i], globals);
array.mergeSets(suggestions, identified);
suggestions.splice(i, 1);
} else {
++ i;
}
}
}
function getHints(cm, options) { function getHints(cm, options) {
const cur = cm.getCursor(); const cur = cm.getCursor();
const token = cm.getTokenAt(cur); const token = cm.getTokenAt(cur);
@ -52,6 +72,8 @@ define(() => {
comp = comp.concat(token.state.knownAgent); comp = comp.concat(token.state.knownAgent);
} }
populateGlobals(comp, cm.options.globals);
const ranges = makeRanges(cm, cur.line, from, token.end); const ranges = makeRanges(cm, cur.line, from, token.end);
let selfValid = false; let selfValid = false;
const list = (comp const list = (comp

View File

@ -26,11 +26,21 @@ define(['core/ArrayUtilities'], (array) => {
',': {type: 'operator', suggest: true, then: {'': 1}}, ',': {type: 'operator', suggest: true, then: {'': 1}},
'\n': end, '\n': end,
}}; }};
const agentListToEnd = {type: 'variable', suggest: 'Agent', then: { const agentListToText = {type: 'variable', suggest: 'Agent', then: {
'': 0, '': 0,
',': {type: 'operator', suggest: true, then: {'': 1}}, ',': {type: 'operator', suggest: true, then: {'': 1}},
':': {type: 'operator', suggest: true, then: {'': textToEnd}}, ':': {type: 'operator', suggest: true, then: {'': textToEnd}},
}}; }};
const agentList2ToText = {type: 'variable', suggest: 'Agent', then: {
'': 0,
',': {type: 'operator', suggest: true, then: {'': agentListToText}},
':': CM_ERROR,
}};
const singleAgentToText = {type: 'variable', suggest: 'Agent', then: {
'': 0,
',': CM_ERROR,
':': {type: 'operator', suggest: true, then: {'': textToEnd}},
}};
const agentToOptText = {type: 'variable', suggest: 'Agent', then: { const agentToOptText = {type: 'variable', suggest: 'Agent', then: {
'': 0, '': 0,
':': {type: 'operator', suggest: true, then: { ':': {type: 'operator', suggest: true, then: {
@ -46,12 +56,12 @@ define(['core/ArrayUtilities'], (array) => {
suggest: [side + ' of ', side + ': '], suggest: [side + ' of ', side + ': '],
then: { then: {
'of': {type: 'keyword', suggest: true, then: { 'of': {type: 'keyword', suggest: true, then: {
'': agentListToEnd, '': agentListToText,
}}, }},
':': {type: 'operator', suggest: true, then: { ':': {type: 'operator', suggest: true, then: {
'': textToEnd, '': textToEnd,
}}, }},
'': agentListToEnd, '': agentListToText,
}, },
}; };
} }
@ -122,7 +132,17 @@ define(['core/ArrayUtilities'], (array) => {
'': textToEnd, '': textToEnd,
}}, }},
'theme': {type: 'keyword', suggest: true, then: { 'theme': {type: 'keyword', suggest: true, then: {
'': textToEnd, '': {
type: 'string',
suggest: {
global: 'themes',
suffix: '\n',
},
then: {
'': 0,
'\n': end,
},
},
}}, }},
'terminators': {type: 'keyword', suggest: true, then: { 'terminators': {type: 'keyword', suggest: true, then: {
'none': {type: 'keyword', suggest: true, then: {}}, 'none': {type: 'keyword', suggest: true, then: {}},
@ -166,17 +186,17 @@ define(['core/ArrayUtilities'], (array) => {
}}, }},
'note': {type: 'keyword', suggest: true, then: { 'note': {type: 'keyword', suggest: true, then: {
'over': {type: 'keyword', suggest: true, then: { 'over': {type: 'keyword', suggest: true, then: {
'': agentListToEnd, '': agentListToText,
}}, }},
'left': makeSideNote('left'), 'left': makeSideNote('left'),
'right': makeSideNote('right'), 'right': makeSideNote('right'),
'between': {type: 'keyword', suggest: true, then: { 'between': {type: 'keyword', suggest: true, then: {
'': agentListToEnd, '': agentList2ToText,
}}, }},
}}, }},
'state': {type: 'keyword', suggest: 'state over ', then: { 'state': {type: 'keyword', suggest: 'state over ', then: {
'over': {type: 'keyword', suggest: true, then: { 'over': {type: 'keyword', suggest: true, then: {
'': agentListToEnd, '': singleAgentToText,
}}, }},
}}, }},
'text': {type: 'keyword', suggest: true, then: { 'text': {type: 'keyword', suggest: true, then: {
@ -204,6 +224,9 @@ define(['core/ArrayUtilities'], (array) => {
} }
function cmGetVarSuggestions(state, previous, current) { function cmGetVarSuggestions(state, previous, current) {
if(typeof current.suggest === 'object' && current.suggest.global) {
return [current.suggest];
}
if( if(
typeof current.suggest !== 'string' || typeof current.suggest !== 'string' ||
previous.suggest === current.suggest previous.suggest === current.suggest

View File

@ -589,6 +589,12 @@ define([
this.sizer.detach(); this.sizer.detach();
} }
getThemeNames() {
return (Array.from(this.themes.keys())
.filter((name) => (name !== ''))
);
}
getAgentX(name) { getAgentX(name) {
return this.agentInfos.get(name).x; return this.agentInfos.get(name).x;
} }

View File

@ -24,12 +24,17 @@ define([
function getArrowShort(theme) { function getArrowShort(theme) {
const arrow = theme.connect.arrow; const arrow = theme.connect.arrow;
const h = arrow.height / 2; const join = arrow.attrs['stroke-linejoin'] || 'miter';
const w = arrow.width;
const t = arrow.attrs['stroke-width'] * 0.5; const t = arrow.attrs['stroke-width'] * 0.5;
const lineStroke = theme.agentLineAttrs['stroke-width'] * 0.5; const lineStroke = theme.agentLineAttrs['stroke-width'] * 0.5;
const arrowDistance = t * Math.sqrt((w * w) / (h * h) + 1); if(join === 'round') {
return lineStroke + arrowDistance; return lineStroke + t;
} else {
const h = arrow.height / 2;
const w = arrow.width;
const arrowDistance = t * Math.sqrt((w * w) / (h * h) + 1);
return lineStroke + arrowDistance;
}
} }
class Connect extends BaseComponent { class Connect extends BaseComponent {

View File

@ -4,7 +4,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
const LINE_HEIGHT = 1.3; const LINE_HEIGHT = 1.3;
const SETTINGS = { const SETTINGS = {
titleMargin: 10, titleMargin: 12,
outerMargin: 5, outerMargin: 5,
agentMargin: 8, agentMargin: 8,
actionMargin: 5, actionMargin: 5,
@ -40,6 +40,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
'fill': 'none', 'fill': 'none',
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 3, 'stroke-width': 3,
'stroke-linecap': 'round',
}, },
}, },
bar: { bar: {
@ -48,6 +49,8 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 3, 'stroke-width': 3,
'height': 4, 'height': 4,
'rx': 2,
'ry': 2,
}, },
}, },
fade: { fade: {
@ -60,7 +63,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
}, },
connect: { connect: {
loopbackRadius: 6, loopbackRadius: 8,
lineAttrs: { lineAttrs: {
'solid': { 'solid': {
'fill': 'none', 'fill': 'none',
@ -71,7 +74,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
'fill': 'none', 'fill': 'none',
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 3, 'stroke-width': 3,
'stroke-dasharray': '4, 2', 'stroke-dasharray': '10, 4',
}, },
}, },
arrow: { arrow: {
@ -79,13 +82,14 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
height: 12, height: 12,
attrs: { attrs: {
'fill': '#000000', 'fill': '#000000',
'stroke-width': 0, 'stroke': '#000000',
'stroke-linejoin': 'miter', 'stroke-width': 3,
'stroke-linejoin': 'round',
}, },
}, },
label: { label: {
padding: 6, padding: 6,
margin: {top: 2, bottom: 1}, margin: {top: 2, bottom: 3},
attrs: { attrs: {
'font-family': 'sans-serif', 'font-family': 'sans-serif',
'font-size': 8, 'font-size': 8,
@ -100,10 +104,10 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
}, },
mask: { mask: {
padding: { padding: {
top: 0, top: 1,
left: 3, left: 5,
right: 3, right: 5,
bottom: 1, bottom: 3,
}, },
}, },
}, },
@ -116,28 +120,28 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
boxAttrs: { boxAttrs: {
'fill': 'none', 'fill': 'none',
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 1.5, 'stroke-width': 4,
'rx': 2, 'rx': 5,
'ry': 2, 'ry': 5,
}, },
section: { section: {
padding: { padding: {
top: 3, top: 3,
bottom: 2, bottom: 4,
}, },
mode: { mode: {
padding: { padding: {
top: 1, top: 2,
left: 3, left: 5,
right: 3, right: 5,
bottom: 0, bottom: 1,
}, },
boxAttrs: { boxAttrs: {
'fill': '#FFFFFF', 'fill': '#FFFFFF',
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 3, 'stroke-width': 2,
'rx': 2, 'rx': 3,
'ry': 2, 'ry': 3,
}, },
labelAttrs: { labelAttrs: {
'font-family': 'sans-serif', 'font-family': 'sans-serif',
@ -149,7 +153,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
}, },
label: { label: {
padding: { padding: {
top: 1, top: 2,
left: 5, left: 5,
right: 3, right: 3,
bottom: 0, bottom: 0,
@ -165,8 +169,8 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
separator: { separator: {
attrs: { attrs: {
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 1.5, 'stroke-width': 2,
'stroke-dasharray': '4, 2', 'stroke-dasharray': '5, 3',
}, },
}, },
}, },
@ -187,12 +191,13 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
}, },
'note': { 'note': {
margin: {top: 0, left: 5, right: 5, bottom: 0}, margin: {top: 0, left: 5, right: 5, bottom: 0},
padding: {top: 5, left: 5, right: 10, bottom: 5}, padding: {top: 3, left: 3, right: 10, bottom: 3},
overlap: {left: 10, right: 10}, overlap: {left: 10, right: 10},
boxRenderer: SVGShapes.renderNote.bind(null, { boxRenderer: SVGShapes.renderNote.bind(null, {
'fill': '#FFFFFF', 'fill': '#FFFFFF',
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 1, 'stroke-width': 2,
'stroke-linejoin': 'round',
}, { }, {
'fill': 'none', 'fill': 'none',
'stroke': '#000000', 'stroke': '#000000',
@ -206,12 +211,12 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
}, },
'state': { 'state': {
margin: {top: 0, left: 5, right: 5, bottom: 0}, margin: {top: 0, left: 5, right: 5, bottom: 0},
padding: {top: 7, left: 7, right: 7, bottom: 7}, padding: {top: 5, left: 7, right: 7, bottom: 5},
overlap: {left: 10, right: 10}, overlap: {left: 10, right: 10},
boxRenderer: SVGShapes.renderBox.bind(null, { boxRenderer: SVGShapes.renderBox.bind(null, {
'fill': '#FFFFFF', 'fill': '#FFFFFF',
'stroke': '#000000', 'stroke': '#000000',
'stroke-width': 1, 'stroke-width': 3,
'rx': 10, 'rx': 10,
'ry': 10, 'ry': 10,
}), }),
@ -225,6 +230,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
titleAttrs: { titleAttrs: {
'font-family': 'sans-serif', 'font-family': 'sans-serif',
'font-weight': 'bolder',
'font-size': 20, 'font-size': 20,
'line-height': LINE_HEIGHT, 'line-height': LINE_HEIGHT,
'text-anchor': 'middle', 'text-anchor': 'middle',