Skip to content

Commit

Permalink
Merge pull request #581 from aminya/fixRemoval
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya authored Sep 26, 2020
2 parents a974461 + d5778ae commit 3162586
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 32 deletions.
100 changes: 71 additions & 29 deletions lib/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import debounce from 'sb-debounce'
import disposableEvent from 'disposable-event'
import { CompositeDisposable, Disposable, Emitter, Range } from 'atom'
import type { TextEditor, BufferMarker, TextEditorGutter, Point } from 'atom'
// $FlowIgnore: Cursor is a type
import type { TextEditor, BufferMarker, TextEditorGutter, Point, Cursor } from 'atom'

import Tooltip from '../tooltip'
import { $range, filterMessagesByRangeOrPoint } from '../helpers'
Expand All @@ -14,8 +15,8 @@ class Editor {
gutter: ?TextEditorGutter
tooltip: ?Tooltip
emitter: Emitter
markers: Map<LinterMessage, BufferMarker>
messages: Set<LinterMessage>
markers: Map<string, Array<BufferMarker>>
messages: Map<string, LinterMessage>
textEditor: TextEditor
showTooltip: boolean
subscriptions: CompositeDisposable
Expand All @@ -25,15 +26,23 @@ class Editor {
showDecorations: boolean
showProviderName: boolean
ignoreTooltipInvocation: boolean
currentLineMarker: ?BufferMarker
lastRange: ?Range
lastEmpty: ?Range
lastCursorPositions: WeakMap<Cursor, Point>

constructor(textEditor: TextEditor) {
this.tooltip = null
this.emitter = new Emitter()
this.markers = new Map()
this.messages = new Set()
this.messages = new Map()
this.textEditor = textEditor
this.subscriptions = new CompositeDisposable()
this.ignoreTooltipInvocation = false
this.currentLineMarker = null
this.lastRange = null
this.lastEmpty = null
this.lastCursorPositions = new WeakMap()

this.subscriptions.add(this.emitter)
this.subscriptions.add(
Expand Down Expand Up @@ -96,12 +105,11 @@ class Editor {
}),
)

const lastCursorPositions = new WeakMap()
this.subscriptions.add(
textEditor.onDidChangeCursorPosition(({ cursor, newBufferPosition }) => {
const lastBufferPosition = lastCursorPositions.get(cursor)
const lastBufferPosition = this.lastCursorPositions.get(cursor)
if (!lastBufferPosition || !lastBufferPosition.isEqual(newBufferPosition)) {
lastCursorPositions.set(cursor, newBufferPosition)
this.lastCursorPositions.set(cursor, newBufferPosition)
this.ignoreTooltipInvocation = false
}
if (this.tooltipFollows === 'Mouse') {
Expand All @@ -113,7 +121,7 @@ class Editor {
textEditor.getBuffer().onDidChangeText(() => {
const cursors = textEditor.getCursors()
cursors.forEach(cursor => {
lastCursorPositions.set(cursor, cursor.getBufferPosition())
this.lastCursorPositions.set(cursor, cursor.getBufferPosition())
})
if (this.tooltipFollows !== 'Mouse') {
this.ignoreTooltipInvocation = true
Expand All @@ -127,9 +135,6 @@ class Editor {
listenForCurrentLine() {
this.subscriptions.add(
this.textEditor.observeCursors(cursor => {
let marker
let lastRange
let lastEmpty
const handlePositionChange = ({ start, end }) => {
const gutter = this.gutter
if (!gutter || this.subscriptions.disposed) return
Expand All @@ -144,17 +149,20 @@ class Editor {
if (start.row !== end.row && currentRange.end.column === 0) {
linesRange.end.row--
}
if (lastRange && lastRange.isEqual(linesRange) && currentEmpty === lastEmpty) return
if (marker) marker.destroy()
lastRange = linesRange
lastEmpty = currentEmpty
if (this.lastRange && this.lastRange.isEqual(linesRange) && currentEmpty === this.lastEmpty) return
if (this.currentLineMarker) {
this.currentLineMarker.destroy()
this.currentLineMarker = null
}
this.lastRange = linesRange
this.lastEmpty = currentEmpty

marker = this.textEditor.markScreenRange(linesRange, {
this.currentLineMarker = this.textEditor.markScreenRange(linesRange, {
invalidate: 'never',
})
const item = document.createElement('span')
item.className = `line-number cursor-line linter-cursor-line ${currentEmpty ? 'cursor-line-no-selection' : ''}`
gutter.decorateMarker(marker, {
gutter.decorateMarker(this.currentLineMarker, {
item,
class: 'linter-row',
})
Expand All @@ -178,7 +186,10 @@ class Editor {
)
subscriptions.add(
new Disposable(function() {
if (marker) marker.destroy()
if (this.currentLineMarker) {
this.currentLineMarker.destroy()
this.currentLineMarker = null
}
}),
)
this.subscriptions.add(subscriptions)
Expand Down Expand Up @@ -247,8 +258,13 @@ class Editor {
name: 'linter-ui-default',
priority,
})
this.markers.forEach((marker, message) => {
this.decorateMarker(message, marker, 'gutter')
this.markers.forEach((markers: Array<BufferMarker>, key: string) => {
const message = this.messages.get(key)
if (message) {
for (const marker of markers) {
this.decorateMarker(message, marker, 'gutter')
}
}
})
}
removeGutter() {
Expand Down Expand Up @@ -278,6 +294,14 @@ class Editor {
}

this.tooltip = new Tooltip(messages, position, this.textEditor)

// save markers of the tooltip (for destorying them in this.apply)
messages.forEach(message => {
// $FlowIgnore: this.tooltip is not null
this.saveMarker(message.key, this.tooltip.marker)
})

// $FlowIgnore: this.tooltip is not null
this.tooltip.onDidDestroy(() => {
this.tooltip = null
})
Expand All @@ -292,12 +316,7 @@ class Editor {

for (let i = 0, length = removed.length; i < length; i++) {
const message = removed[i]
const marker = this.markers.get(message)
if (marker) {
marker.destroy()
}
this.messages.delete(message)
this.markers.delete(message)
this.destroyMarker(message.key)
}

for (let i = 0, length = added.length; i < length; i++) {
Expand All @@ -310,8 +329,6 @@ class Editor {
const marker = textBuffer.markRange(markerRange, {
invalidate: 'never',
})
this.markers.set(message, marker)
this.messages.add(message)
this.decorateMarker(message, marker)
marker.onDidChange(({ oldHeadPosition, newHeadPosition, isValid }) => {
if (!isValid || (newHeadPosition.row === 0 && oldHeadPosition.row !== 0)) {
Expand All @@ -325,7 +342,10 @@ class Editor {

this.updateTooltip(this.cursorPosition)
}
decorateMarker(message: LinterMessage, marker: Object, paint: 'gutter' | 'editor' | 'both' = 'both') {
decorateMarker(message: LinterMessage, marker: BufferMarker, paint: 'gutter' | 'editor' | 'both' = 'both') {
this.saveMarker(message.key, marker)
this.messages.set(message.key, message)

if (paint === 'both' || paint === 'editor') {
this.textEditor.decorateMarker(marker, {
type: 'text',
Expand All @@ -343,6 +363,28 @@ class Editor {
})
}
}

// add marker to the message => marker map
saveMarker(key: string, marker: BufferMarker) {
const allMarkers = this.markers.get(key) || []
allMarkers.push(marker)
this.markers.set(key, allMarkers)
}

// destroy markers of a key
destroyMarker(key: string) {
const markers = this.markers.get(key)
if (markers) {
markers.forEach(marker => {
if (marker) {
marker.destroy()
}
})
}
this.markers.delete(key)
this.messages.delete(key)
}

onDidDestroy(callback: Function): Disposable {
return this.emitter.on('did-destroy', callback)
}
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function filterMessages(
}

export function filterMessagesByRangeOrPoint(
messages: Set<LinterMessage> | Array<LinterMessage>,
messages: Set<LinterMessage> | Array<LinterMessage> | Map<string, LinterMessage>,
filePath: string,
rangeOrPoint: Point | Range,
): Array<LinterMessage> {
Expand Down
7 changes: 5 additions & 2 deletions lib/tooltip/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ class TooltipElement {
})
ReactDOM.render(<linter-messages>{children}</linter-messages>, this.element)
}
isValid(position: Point, messages: Set<LinterMessage>): boolean {
isValid(position: Point, messages: Map<string, LinterMessage>): boolean {
if (this.messages.length !== 1 || !messages.has(this.messages[0].key)) {
return false
}
const range = $range(this.messages[0])
return !!(this.messages.length === 1 && messages.has(this.messages[0]) && range && range.containsPoint(position))
return Boolean(range && range.containsPoint(position))
}
onDidDestroy(callback: () => any): Disposable {
this.emitter.on('did-destroy', callback)
Expand Down

0 comments on commit 3162586

Please sign in to comment.