@@ -104,9 +104,9 @@ define(function (require, exports, module) {
104104 }
105105
106106
107- function _getScrollbar ( editor ) {
107+ function _getScrollbar ( editorInstance ) {
108108 // Be sure to select only the direct descendant, not also elements within nested inline editors
109- return $ ( editor . getRootElement ( ) ) . children ( ".CodeMirror-vscrollbar" ) ;
109+ return $ ( editorInstance . getRootElement ( ) ) . children ( ".CodeMirror-vscrollbar" ) ;
110110 }
111111
112112 /**
@@ -123,29 +123,47 @@ define(function (require, exports, module) {
123123 trackHt -= trackOffset * 2 ;
124124 } else {
125125 // No scrollbar: use the height of the entire code content
126- var codeContainer = $ ( editor . getRootElement ( ) ) . find ( "> .CodeMirror-scroll > .CodeMirror-sizer > div > .CodeMirror-lines > div" ) [ 0 ] ;
126+ var codeContainer = $ ( editor . getRootElement ( ) )
127+ . find ( "> .CodeMirror-scroll > .CodeMirror-sizer > div > .CodeMirror-lines > div" ) [ 0 ] ;
127128 trackHt = codeContainer . offsetHeight ;
128129 trackOffset = codeContainer . offsetTop ;
129130 }
130131 }
131132
133+ function _getTop ( editorInstance , pos ) {
134+ let cm = editorInstance . _codeMirror ,
135+ editorHt = cm . getScrollerElement ( ) . scrollHeight ,
136+ cursorTop ;
137+
138+ let wrapping = cm . getOption ( "lineWrapping" ) ,
139+ singleLineH = wrapping && cm . defaultTextHeight ( ) * 1.5 ;
140+ let curLine = pos . line ;
141+ let curLineObj = cm . getLineHandle ( curLine ) ;
142+ if ( wrapping && curLineObj . height > singleLineH ) {
143+ cursorTop = cm . charCoords ( pos , "local" ) . top ;
144+ } else {
145+ cursorTop = cm . heightAtLine ( curLineObj , "local" ) ;
146+ }
147+ // return top
148+ return ( Math . round ( cursorTop / editorHt * trackHt ) + trackOffset ) - 1 ; // 1px Centering correction
149+ }
150+
151+ const MARKER_HEIGHT = 2 ;
152+
132153 /**
133- * Add all the given tickmarks to the DOM in a batch
154+ * Add merged tickmarks to the scrollbar track
134155 * @private
135156 */
136157 function _renderMarks ( posArray ) {
137- var html = "" ,
138- cm = editor . _codeMirror ,
158+ let cm = editor . _codeMirror ,
139159 editorHt = cm . getScrollerElement ( ) . scrollHeight ;
140160
141- // We've pretty much taken these vars and the getY function from CodeMirror's annotatescrollbar addon
142- // https://github.com/codemirror/CodeMirror/blob/master/addon/scroll/annotatescrollbar.js
143- var wrapping = cm . getOption ( "lineWrapping" ) ,
161+ let wrapping = cm . getOption ( "lineWrapping" ) ,
144162 singleLineH = wrapping && cm . defaultTextHeight ( ) * 1.5 ,
145163 curLine = null ,
146164 curLineObj = null ;
147165
148- function getY ( cm , pos ) {
166+ function getY ( pos ) {
149167 if ( curLine !== pos . line ) {
150168 curLine = pos . line ;
151169 curLineObj = cm . getLineHandle ( curLine ) ;
@@ -156,13 +174,41 @@ define(function (require, exports, module) {
156174 return cm . heightAtLine ( curLineObj , "local" ) ;
157175 }
158176
177+ var markPositions = [ ] ;
178+
179+ // Convert line positions to scrollbar positions
159180 posArray . forEach ( function ( pos ) {
160- var cursorTop = getY ( cm , pos ) ,
181+ var cursorTop = getY ( pos ) ,
161182 top = Math . round ( cursorTop / editorHt * trackHt ) + trackOffset ;
162- top -- ; // subtract ~1/2 the ht of a tickmark to center it on ideal pos
183+ top -- ; // Centering correction
184+ markPositions . push ( { top : top , bottom : top + MARKER_HEIGHT } ) ; // Default height is 2px
185+ } ) ;
163186
164- html += "<div class='tickmark' style='top:" + top + "px'></div>" ;
187+ // Sort positions by top coordinate
188+ markPositions . sort ( ( a , b ) => a . top - b . top ) ;
189+
190+ // Merge overlapping or adjacent tickmarks
191+ var mergedMarks = [ ] ;
192+ markPositions . forEach ( ( { top, bottom } ) => {
193+ if ( mergedMarks . length > 0 ) {
194+ let lastMark = mergedMarks [ mergedMarks . length - 1 ] ;
195+
196+ if ( top <= lastMark . bottom + 1 ) {
197+ // Extend the existing mark
198+ lastMark . bottom = Math . max ( lastMark . bottom , bottom ) ;
199+ lastMark . height = lastMark . bottom - lastMark . top ; // Adjust height
200+ return ;
201+ }
202+ }
203+ // Create a new mark
204+ mergedMarks . push ( { top, bottom, height : bottom - top } ) ;
165205 } ) ;
206+
207+ // Generate and insert tickmarks into the DOM
208+ var html = mergedMarks . map ( ( { top, height } ) =>
209+ `<div class='tickmark' style='top:${ top } px; height:${ height } px;'></div>`
210+ ) . join ( "" ) ;
211+
166212 $ ( ".tickmark-track" , editor . getRootElement ( ) ) . append ( $ ( html ) ) ;
167213 }
168214
@@ -239,11 +285,15 @@ define(function (require, exports, module) {
239285 function markCurrent ( index ) {
240286 // Remove previous highlight first
241287 if ( $markedTickmark ) {
242- $markedTickmark . removeClass ( "tickmark-current" ) ;
288+ $markedTickmark . remove ( ) ;
243289 $markedTickmark = null ;
244290 }
245291 if ( index !== - 1 ) {
246- $markedTickmark = $ ( ".tickmark-track > .tickmark" , editor . getRootElement ( ) ) . eq ( index ) . addClass ( "tickmark-current" ) ;
292+ const parkPos = marks [ index ] ;
293+ const top = _getTop ( editor , parkPos ) ;
294+ $markedTickmark = $ (
295+ `<div class='tickmark tickmark-current' style='top:${ top } px; height:${ MARKER_HEIGHT } px;'></div>` ) ;
296+ $ ( ".tickmark-track " ) . append ( $markedTickmark ) ;
247297 }
248298 }
249299
0 commit comments