summary refs log tree commit diff stats
path: root/compiler/main.nim
Commit message (Expand)AuthorAgeFilesLines
...
* implements experimental new config system based on NimScriptAraq2015-08-161-1/+2
* Reset terminal colors before running compiled programdef2015-07-101-0/+1
* Merge pull request #3020 from flaviut/rename-crc-to-hashAndreas Rumpf2015-07-051-1/+1
|\
| * CRC -> HashFlaviu Tamas2015-07-031-1/+1
* | Introduce NotesVerbosity defining verbosity levelsAdam Strzelecki2015-07-031-3/+2
* | fixes #2633Araq2015-07-031-1/+1
|/
* Clean up stdin file reading of compiler.def2015-05-161-1/+1
* Initialize c compiler variables later ...def2015-03-281-0/+1
* fixes #1868Araq2015-03-121-2/+4
* When compiling from stdin write binary to stdinfiledef2015-02-281-1/+1
* fixes #1601Araq2015-02-051-1/+0
* nimsuggest: sane dirty buffer handlingAraq2015-01-291-3/+3
* nimsuggest: first versionAraq2015-01-271-12/+4
* Merge pull request #1889 from ramnes/develAndreas Rumpf2015-01-071-1/+1
|\
| * Happy new year!Guillaume Gelin2015-01-061-1/+1
* | minor cleanupsAraq2015-01-071-20/+0
|/
* implemented mixed mode codegenAraq2014-10-031-2/+0
* Fix 'doc' command.Dominik Picheta2014-09-131-0/+2
* 'pretty' command does not exist anymore; improvements for nimfixAraq2014-09-101-9/+1
* some improvements for nimfixAraq2014-09-091-3/+0
* nimfix handles helloworldAraq2014-09-061-36/+1
* fixes #903, fixes #1513Araq2014-09-031-6/+0
* Nimrod renamed to NimAraq2014-08-281-1/+1
* gpp -> gccEXetoC2014-05-091-1/+1
* fixed constant typo (SimulateCaasMemReset)Simon Hafner2014-05-021-3/+3
* compiler prepared for the new comment handlingAraq2014-04-301-0/+1
* case consistency for evalffiAraq2014-02-011-3/+4
* it's the year 2014Araq2014-01-191-1/+1
* case consistency: cs:partial bootstraps on windowsAraq2013-12-291-2/+2
* case consistency: next stepsAraq2013-12-291-7/+7
* case consistency part 4Araq2013-12-271-52/+52
* case consistency part 1Araq2013-12-271-16/+16
* Merge branch 'master' of https://github.com/Araq/Nimrod into vm2Araq2013-12-231-26/+32
|\
| * Added jsondoc compiler switchErik O'Leary2013-12-121-26/+32
* | Merge branch 'master' into vm2Araq2013-12-131-1/+3
|\|
| * in successful compilations with verbosity:0, all output is suppressed (useful...Zahary Karadjov2013-12-101-1/+3
* | compiler bootstraps with new VMAraq2013-10-151-1/+1
|/
* Take into account dirty buffers in suggest output; Fixes zah/nimrod.vim#14Zahary Karadjov2013-08-071-1/+5
* 'nimrod pretty': next steps, doesn't work yetAraq2013-07-291-0/+1
* 'nimrod pretty' command: next stepsAraq2013-07-291-2/+9
* 'modules' module from 'main'; minor bugfixesAraq2013-07-201-210/+7
* refactorings for the eval engine; bugfix: clean templates as accessorsAraq2013-07-191-0/+12
* fix compiling after suggestZahary Karadjov2013-05-051-23/+17
* support suggest after compile in caas modeZahary Karadjov2013-05-051-1/+6
* bugfix: compiling after idetools usage is now possible in caas modeZahary Karadjov2013-05-051-0/+10
* experimental support for answering idetools --def requests fromZahary Karadjov2013-05-041-8/+12
* nimrod dump can now produce a machine readable json reportZahary Karadjov2013-05-011-5/+35
* bugfix: fix linking when symbol files are usedZahary Karadjov2013-04-081-2/+2
* next steps to make symbol files work againAraq2013-04-081-1/+2
* Removes executable bit for text files.Grzegorz Adam Hankiewicz2013-03-161-0/+0
/span>).fill(color); return new Picture(width, height, pixels); } pixel(x, y) { return this.pixels[x + y * this.width]; } draw(pixels) { let copy = this.pixels.slice(); for (let { x, y, color } of pixels) { copy[x + y * this.width] = color; } return new Picture(this.width, this.height, copy); } } function updateState(state, action) { return Object.assign({}, state, action); } function elt(type, props, ...children) { let dom = document.createElement(type); if (props) Object.assign(dom, props); for (let child of children) { if (typeof child != "string") dom.appendChild(child); else dom.appendChild(document.createTextNode(child)); } return dom; } const scale = 38; class PictureCanvas { constructor(picture, pointerDown) { this.dom = elt("canvas", { onmousedown: (event) => this.mouse(event, pointerDown), ontouchstart: (event) => this.touch(event, pointerDown), }); this.syncState(picture); } syncState(picture) { if (this.picture == picture) return; this.picture = picture; drawPicture(this.picture, this.dom, scale); } } function drawPicture(picture, canvas, scale) { canvas.width = picture.width * scale; canvas.height = picture.height * scale; let cx = canvas.getContext("2d"); for (let y = 0; y < picture.height; y++) { for (let x = 0; x < picture.width; x++) { cx.fillStyle = picture.pixel(x, y); cx.fillRect(x * scale, y * scale, scale, scale); } } } PictureCanvas.prototype.mouse = function (downEvent, onDown) { if (downEvent.button != 0) return; let pos = pointerPosition(downEvent, this.dom); let onMove = onDown(pos); if (!onMove) return; let move = (moveEvent) => { if (moveEvent.buttons == 0) { this.dom.removeEventListener("mousemove", move); } else { let newPos = pointerPosition(moveEvent, this.dom); if (newPos.x == pos.x && newPos.y == pos.y) return; pos = newPos; onMove(newPos); } }; this.dom.addEventListener("mousemove", move); }; function pointerPosition(pos, domNode) { let rect = domNode.getBoundingClientRect(); return { x: Math.floor((pos.clientX - rect.left) / scale), y: Math.floor((pos.clientY - rect.top) / scale), }; } PictureCanvas.prototype.touch = function (startEvent, onDown) { let pos = pointerPosition(startEvent.touches[0], this.dom); let onMove = onDown(pos); startEvent.preventDefault(); if (!onMove) return; let move = (moveEvent) => { let newPos = pointerPosition(moveEvent.touches[0], this.dom); if (newPos.x == pos.x && newPos.y == pos.y) return; pos = newPos; onMove(newPos); }; let end = () => { this.dom.removeEventListener("touchmove", move); this.dom.removeEventListener("touchend", end); }; this.dom.addEventListener("touchmove", move); this.dom.addEventListener("touchend", end); }; class PixelEditor { constructor(state, config) { let { tools, controls, dispatch } = config; this.state = state; this.canvas = new PictureCanvas(state.picture, (pos) => { let tool = tools[this.state.tool]; let onMove = tool(pos, this.state, dispatch); if (onMove) return (pos) => onMove(pos, this.state); }); this.controls = controls.map((Control) => new Control(state, config)); this.dom = elt( "div", {}, this.canvas.dom, elt("br"), ...this.controls.reduce((a, c) => a.concat(" ", c.dom), []) ); } syncState(state) { this.state = state; this.canvas.syncState(state.picture); for (let ctrl of this.controls) ctrl.syncState(state); } } class ToolSelect { constructor(state, { tools, dispatch }) { this.select = elt( "select", { onchange: () => dispatch({ tool: this.select.value }), }, ...Object.keys(tools).map((name) => elt( "option", { selected: name == state.tool, }, name ) ) ); this.dom = elt("label", null, "🖌 Tool: ", this.select); } syncState(state) { this.select.value = state.tool; } } class ColorSelect { constructor(state, { dispatch }) { this.input = elt("input", { type: "color", value: state.color, onchange: () => dispatch({ color: this.input.value }), }); this.dom = elt("label", null, "🎨 Color: ", this.input); } syncState(state) { this.input.value = state.color; } } function draw(pos, state, dispatch) { function drawPixel({ x, y }, state) { let drawn = { x, y, color: state.color }; dispatch({ picture: state.picture.draw([drawn]) }); } drawPixel(pos, state); return drawPixel; } function rectangle(start, state, dispatch) { function drawRectangle(pos) { let xStart = Math.min(start.x, pos.x); let yStart = Math.min(start.y, pos.y); let xEnd = Math.max(start.x, pos.x); let yEnd = Math.max(start.y, pos.y); let drawn = []; for (let y = yStart; y <= yEnd; y++) { for (let x = xStart; x <= xEnd; x++) { drawn.push({ x, y, color: state.color }); } } dispatch({ picture: state.picture.draw(drawn) }); } drawRectangle(start); return drawRectangle; } const around = [ { dx: -1, dy: 0 }, { dx: 1, dy: 0 }, { dx: 0, dy: -1 }, { dx: 0, dy: 1 }, ]; function fill({ x, y }, state, dispatch) { let targetColor = state.picture.pixel(x, y); let drawn = [{ x, y, color: state.color }]; for (let done = 0; done < drawn.length; done++) { for (let { dx, dy } of around) { let x = drawn[done].x + dx, y = drawn[done].y + dy; if ( x >= 0 && x < state.picture.width && y >= 0 && y < state.picture.height && state.picture.pixel(x, y) == targetColor && !drawn.some((p) => p.x == x && p.y == y) ) { drawn.push({ x, y, color: state.color }); } } } dispatch({ picture: state.picture.draw(drawn) }); } function pick(pos, state, dispatch) { dispatch({ color: state.picture.pixel(pos.x, pos.y) }); } class SaveButton { constructor(state) { this.picture = state.picture; this.dom = elt( "button", { onclick: () => this.save(), }, "💾 Save" ); } save() { let canvas = elt("canvas"); drawPicture(this.picture, canvas, 1); let link = elt("a", { href: canvas.toDataURL(), download: "pixelart.png", }); document.body.appendChild(link); link.click(); link.remove(); } syncState(state) { this.picture = state.picture; } } class LoadButton { constructor(_, { dispatch }) { this.dom = elt( "button", { onclick: () => startLoad(dispatch), }, "📁 Load" ); } syncState() {} } function startLoad(dispatch) { let input = elt("input", { type: "file", onchange: () => finishLoad(input.files[0], dispatch), }); document.body.appendChild(input); input.click(); input.remove(); } function finishLoad(file, dispatch) { if (file == null) return; let reader = new FileReader(); reader.addEventListener("load", () => { let image = elt("img", { onload: () => dispatch({ picture: pictureFromImage(image), }), src: reader.result, }); }); reader.readAsDataURL(file); } function pictureFromImage(image) { let width = Math.min(16, image.width); let height = Math.min(16, image.height); let canvas = elt("canvas", { width, height }); let cx = canvas.getContext("2d"); cx.drawImage(image, 0, 0); let pixels = []; let { data } = cx.getImageData(0, 0, width, height); function hex(n) { return n.toString(16).padStart(2, "0"); } for (let i = 0; i < data.length; i += 4) { let [r, g, b] = data.slice(i, i + 3); pixels.push("#" + hex(r) + hex(g) + hex(b)); } return new Picture(width, height, pixels); } function historyUpdateState(state, action) { if (action.undo == true) { if (state.done.length == 0) return state; return Object.assign({}, state, { picture: state.done[0], done: state.done.slice(1), doneAt: 0, }); } else if (action.picture && state.doneAt < Date.now() - 1000) { return Object.assign({}, state, action, { done: [state.picture, ...state.done], doneAt: Date.now(), }); } else { return Object.assign({}, state, action); } } class UndoButton { constructor(state, { dispatch }) { this.dom = elt( "button", { onclick: () => dispatch({ undo: true }), disabled: state.done.length == 0, }, "⮪ Undo" ); } syncState(state) { this.dom.disabled = state.done.length == 0; } } const startState = { tool: "draw", color: "#000000", picture: Picture.empty(16, 16, "#f0f0f0"), done: [], doneAt: 0, }; const baseTools = { draw, fill, rectangle, pick }; const baseControls = [ ToolSelect, ColorSelect, SaveButton, LoadButton, UndoButton, ]; function startPixelEditor({ state = startState, tools = baseTools, controls = baseControls, }) { let app = new PixelEditor(state, { tools, controls, dispatch(action) { state = historyUpdateState(state, action); app.syncState(state); }, }); return app.dom; }