From 955bb383dd3e42d7b018dfb6aed5b57e4c2b0bea Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 5 Mar 2012 16:07:22 -0700 Subject: [PATCH] WIP: Start on Renderer, which combines LineWrapper and LineFolder --- spec/atom/renderer-spec.coffee | 69 ++++++++++++++++++++++++++++++++++ src/atom/renderer.coffee | 49 ++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 spec/atom/renderer-spec.coffee create mode 100644 src/atom/renderer.coffee diff --git a/spec/atom/renderer-spec.coffee b/spec/atom/renderer-spec.coffee new file mode 100644 index 000000000..5bcc79482 --- /dev/null +++ b/spec/atom/renderer-spec.coffee @@ -0,0 +1,69 @@ +Renderer = require 'renderer' +Buffer = require 'buffer' + +describe "Renderer", -> + [renderer, buffer] = [] + beforeEach -> + buffer = new Buffer(require.resolve 'fixtures/sample.js') + renderer = new Renderer(buffer) + + describe "line rendering", -> + fdescribe "soft wrapping", -> + beforeEach -> + renderer.setMaxLineLength(50) + + describe "when the line is shorter than the max line length", -> + it "renders the line unchanged", -> + expect(renderer.lineForRow(0).text).toBe buffer.lineForRow(0) + + describe "when the line is empty", -> + it "renders the empty line", -> + expect(renderer.lineForRow(13).text).toBe '' + + describe "when there is a non-whitespace character at the max length boundary", -> + describe "when there is whitespace before the boundary", -> + it "wraps the line at the end of the first whitespace preceding the boundary", -> + expect(renderer.lineForRow(10).text).toBe ' return ' + expect(renderer.lineForRow(11).text).toBe 'sort(left).concat(pivot).concat(sort(right));' + + describe "when there is no whitespace before the boundary", -> + it "wraps the line exactly at the boundary since there's no more graceful place to wrap it", -> + buffer.change([[0, 0], [1, 0]], 'abcdefghijklmnopqrstuvwxyz\n') + renderer.setMaxLineLength(10) + expect(renderer.lineForRow(0).text).toBe 'abcdefghij' + expect(renderer.lineForRow(1).text).toBe 'klmnopqrst' + expect(renderer.lineForRow(2).text).toBe 'uvwxyz' + + describe "when there is a whitespace character at the max length boundary", -> + it "wraps the line at the first non-whitespace character following the boundary", -> + expect(renderer.lineForRow(3).text).toBe ' var pivot = items.shift(), current, left = [], ' + expect(renderer.lineForRow(4).text).toBe 'right = [];' + + describe "when there is a fold placeholder straddling the max length boundary", -> + + describe "folding", -> + describe "when a fold spans multiple lines", -> + + describe "when a fold spans a single line", -> + + describe "when a fold is nested within another fold", -> + + describe "when a fold begins on the line on which another fold ends", -> + + describe "when a fold starts at the beginning of a line", -> + + describe "when a fold ends at the beginning of a line", -> + + describe "when a fold starts on the first line of the buffer", -> + + describe "soft wrapping combined with folding", -> + describe "when a line with a fold placeholder is longer than the max line length", -> + + + + + + + + + diff --git a/src/atom/renderer.coffee b/src/atom/renderer.coffee new file mode 100644 index 000000000..06f129c76 --- /dev/null +++ b/src/atom/renderer.coffee @@ -0,0 +1,49 @@ +Highlighter = require 'highlighter' +LineMap = require 'line-map' +Point = require 'point' + +module.exports = +class Renderer + lineMap: null + highlighter: null + + constructor: (@buffer) -> + @highlighter = new Highlighter(@buffer) + + buildLineMap: -> + @lineMap = new LineMap + @lineMap.insertAtInputRow 0, @buildLinesForBufferRows(0, @buffer.lastRow()) + + setMaxLineLength: (@maxLineLength) -> + @buildLineMap() + + lineForRow: (row) -> + @lineMap.lineForOutputRow(row) + + logLines: -> + @lineMap.logLines() + + buildLinesForBufferRows: (startRow, endRow, startColumn=0) -> + return [] if startRow > endRow + + line = @highlighter.lineForRow(startRow).splitAt(startColumn)[1] + if wrapColumn = @findWrapColumn(line.text) + line = line.splitAt(wrapColumn)[0] + line.outputDelta = new Point(1, 0) + [line].concat @buildLinesForBufferRows(startRow, endRow, startColumn + wrapColumn) + else + [line].concat @buildLinesForBufferRows(startRow + 1, endRow) + + findWrapColumn: (line) -> + return unless line.length > @maxLineLength + + if /\s/.test(line[@maxLineLength]) + # search forward for the start of a word past the boundary + for column in [@maxLineLength..line.length] + return column if /\S/.test(line[column]) + return line.length + else + # search backward for the start of the word on the boundary + for column in [@maxLineLength..0] + return column + 1 if /\s/.test(line[column]) + return @maxLineLength