diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 75422ba65..db91ee991 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -26,21 +26,6 @@ describe('TextEditorComponent', () => { jasmine.useRealClock() }) - function buildComponent (params = {}) { - const buffer = new TextBuffer({text: SAMPLE_TEXT}) - const editor = new TextEditor({buffer}) - const component = new TextEditorComponent({ - model: editor, - rowsPerTile: params.rowsPerTile, - updatedSynchronously: false - }) - const {element} = component - element.style.width = params.width ? params.width + 'px' : '800px' - element.style.height = params.height ? params.height + 'px' : '600px' - if (params.attach !== false) jasmine.attachToDOM(element) - return {component, element, editor} - } - it('renders lines and line numbers for the visible region', async () => { const {component, element, editor} = buildComponent({rowsPerTile: 3}) @@ -184,6 +169,33 @@ describe('TextEditorComponent', () => { expect(Math.round(hiddenInput.getBoundingClientRect().left)).toBe(clientLeftForCharacter(component, 7, 4)) }) + it('soft wraps lines based on the content width when soft wrap is enabled', async () => { + const {component, element, editor} = buildComponent({width: 435, attach: false}) + editor.setSoftWrapped(true) + jasmine.attachToDOM(element) + + expect(getBaseCharacterWidth(component)).toBe(55) + + console.log(element.offsetWidth); + expect(lineNodeForScreenRow(component, 3).textContent).toBe( + ' var pivot = items.shift(), current, left = [], ' + ) + expect(lineNodeForScreenRow(component, 4).textContent).toBe( + ' right = [];' + ) + + await setBaseCharacterWidth(component, 45) + expect(lineNodeForScreenRow(component, 3).textContent).toBe( + ' var pivot = items.shift(), current, left ' + ) + expect(lineNodeForScreenRow(component, 4).textContent).toBe( + ' = [], right = [];' + ) + + const {scroller} = component.refs + expect(scroller.clientWidth).toBe(scroller.scrollWidth) + }) + describe('focus', () => { it('focuses the hidden input element and adds the is-focused class when focused', async () => { assertDocumentFocused() @@ -316,10 +328,7 @@ describe('TextEditorComponent', () => { it('does not horizontally autoscroll by more than half of the visible "base-width" characters if the editor is narrower than twice the scroll margin', async () => { const {component, element, editor} = buildComponent() const {scroller, gutterContainer} = component.refs - element.style.width = - component.getGutterContainerWidth() + - 1.5 * editor.horizontalScrollMargin * component.measurements.baseCharacterWidth + 'px' - await component.getNextUpdatePromise() + await setBaseCharacterWidth(component, 1.5 * editor.horizontalScrollMargin) const contentWidth = scroller.clientWidth - gutterContainer.offsetWidth const contentWidthInCharacters = Math.floor(contentWidth / component.measurements.baseCharacterWidth) @@ -337,6 +346,36 @@ describe('TextEditorComponent', () => { }) }) +function buildComponent (params = {}) { + const buffer = new TextBuffer({text: SAMPLE_TEXT}) + const editor = new TextEditor({buffer}) + const component = new TextEditorComponent({ + model: editor, + rowsPerTile: params.rowsPerTile, + updatedSynchronously: false + }) + const {element} = component + element.style.width = params.width ? params.width + 'px' : '800px' + element.style.height = params.height ? params.height + 'px' : '600px' + if (params.attach !== false) jasmine.attachToDOM(element) + return {component, element, editor} +} + +function getBaseCharacterWidth (component) { + return Math.round( + (component.refs.scroller.clientWidth - component.getGutterContainerWidth()) / + component.measurements.baseCharacterWidth + ) +} + +async function setBaseCharacterWidth (component, widthInCharacters) { + component.element.style.width = + component.getGutterContainerWidth() + + widthInCharacters * component.measurements.baseCharacterWidth + + 'px' + await component.getNextUpdatePromise() +} + function verifyCursorPosition (component, cursorNode, row, column) { const rect = cursorNode.getBoundingClientRect() expect(Math.round(rect.top)).toBe(clientTopForLine(component, row)) diff --git a/src/text-editor-component.js b/src/text-editor-component.js index fbb176684..3719ae75b 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -89,8 +89,10 @@ class TextEditorComponent { } render () { + const model = this.getModel() + let style - if (!this.getModel().getAutoHeight() && !this.getModel().getAutoWidth()) { + if (!model.getAutoHeight() && !model.getAutoWidth()) { style = {contain: 'strict'} } @@ -105,15 +107,32 @@ class TextEditorComponent { tabIndex: -1, on: {focus: this.didFocus} }, - $.div({ref: 'scroller', on: {scroll: this.didScroll}, className: 'scroll-view'}, - $.div({ + $.div( + { + ref: 'scroller', + className: 'scroll-view', + on: {scroll: this.didScroll}, style: { - isolate: 'content', - width: 'max-content', - height: 'max-content', + position: 'absolute', + contain: 'strict', + top: 0, + right: 0, + bottom: 0, + left: 0, + overflowX: model.isSoftWrapped() ? 'hidden' : 'auto', + overflowY: 'auto', backgroundColor: 'inherit' } }, + $.div( + { + style: { + isolate: 'content', + width: 'max-content', + height: 'max-content', + backgroundColor: 'inherit' + } + }, this.renderGutterContainer(), this.renderContent() ) @@ -418,8 +437,8 @@ class TextEditorComponent { didShow () { if (!this.visible) { this.visible = true - this.getModel().setVisible(true) if (!this.measurements) this.performInitialMeasurements() + this.getModel().setVisible(true) this.updateSync() } } @@ -676,11 +695,11 @@ class TextEditorComponent { performInitialMeasurements () { this.measurements = {} + this.measureGutterDimensions() this.measureEditorDimensions() this.measureClientDimensions() this.measureScrollPosition() this.measureCharacterDimensions() - this.measureGutterDimensions() } measureEditorDimensions () { @@ -721,6 +740,7 @@ class TextEditorComponent { } if (clientWidth !== this.measurements.clientWidth) { this.measurements.clientWidth = clientWidth + this.getModel().setWidth(clientWidth - this.getGutterContainerWidth(), true) clientDimensionsChanged = true } this.contentWidthOrHeightChanged = false @@ -733,6 +753,13 @@ class TextEditorComponent { this.measurements.doubleWidthCharacterWidth = this.refs.doubleWidthCharacterSpan.getBoundingClientRect().width this.measurements.halfWidthCharacterWidth = this.refs.halfWidthCharacterSpan.getBoundingClientRect().width this.measurements.koreanCharacterWidth = this.refs.koreanCharacterSpan.getBoundingClientRect().widt + + this.getModel().setDefaultCharWidth( + this.measurements.baseCharacterWidth, + this.measurements.doubleWidthCharacterWidth, + this.measurements.halfWidthCharacterWidth, + this.measurements.koreanCharacterWidth + ) } checkForNewLongestLine () { @@ -905,7 +932,11 @@ class TextEditorComponent { } getContentWidth () { - return Math.round(this.measurements.longestLineWidth + this.measurements.baseCharacterWidth) + if (this.getModel().isSoftWrapped()) { + return this.getClientWidth() - this.getGutterContainerWidth() + } else { + return Math.round(this.measurements.longestLineWidth + this.measurements.baseCharacterWidth) + } } getRowsPerTile () { diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 2c42ecda8..1e8ddcb52 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -3596,7 +3596,10 @@ class TextEditor extends Model @doubleWidthCharWidth = doubleWidthCharWidth @halfWidthCharWidth = halfWidthCharWidth @koreanCharWidth = koreanCharWidth - @displayLayer.reset({}) if @isSoftWrapped() and @getEditorWidthInChars()? + if @isSoftWrapped() + @displayLayer.reset({ + softWrapColumn: @getSoftWrapColumn() + }) defaultCharWidth setHeight: (height, reentrant=false) -> @@ -3614,8 +3617,8 @@ class TextEditor extends Model getAutoWidth: -> @autoWidth ? false - setWidth: (width, reentrant=false) -> - if reentrant + setWidth: (width, fromComponent=false) -> + if fromComponent @update({width}) @width else diff --git a/static/text-editor.less b/static/text-editor.less index 71482f5f5..850907b67 100644 --- a/static/text-editor.less +++ b/static/text-editor.less @@ -1,17 +1,6 @@ atom-text-editor { position: relative; - .scroll-view { - position: absolute; - contain: strict; - top: 0; - right: 0; - bottom: 0; - left: 0; - overflow: auto; - background-color: inherit; - } - .gutter-container { float: left; width: min-content;