firstLine = (visibleLines + startLine - endLine) / 2; firstLine = Math.max(startLine - visibleLines + electricScroll + 1,firstLine); firstLine = Math.min(endLine  - electricScroll,firstLine);
if(endLine - startLine <= visibleLines) firstLine = (startLine + endLine - visibleLines) / 2; else firstLine = buffer.physicalToVirtual(caretLine) - visibleLines / 2;  firstLine = Math.min(firstLine,buffer.getVirtualLineCount() - visibleLines); firstLine = Math.max(firstLine,0);
	public void scrollToCaret(boolean doElectricScroll)	{		if(!buffer.isLineVisible(caretLine))			buffer.expandFoldAt(caretLine,true);		int offset = caret - getLineStartOffset(caretLine);		int virtualCaretLine = buffer.physicalToVirtual(caretLine);		// visibleLines == 0 before the component is realized		// we can't do any proper scrolling then, so we have		// this hack...		if(visibleLines == 0)		{			setFirstLine(caretLine - electricScroll);			return;		}		int electricScroll;		if(doElectricScroll && visibleLines > this.electricScroll * 2)			electricScroll = this.electricScroll;		else			electricScroll = 0;		boolean changed = false;		int _firstLine = firstLine + electricScroll;		int _lastLine = firstLine + visibleLines - electricScroll;		if(virtualCaretLine > _firstLine && virtualCaretLine < _lastLine)		{			// vertical scroll position is correct already		}		else if(_firstLine - virtualCaretLine > visibleLines			|| virtualCaretLine - _lastLine > visibleLines)		{			int startLine, endLine;			Selection s = getSelectionAtOffset(caret);			if(s == null)				startLine = endLine = buffer.physicalToVirtual(caretLine);			else			{				startLine = buffer.physicalToVirtual(s.startLine);				endLine = buffer.physicalToVirtual(s.endLine);			}			// center {markLine,caretLine} on screen			firstLine = (visibleLines + startLine - endLine) / 2; 			firstLine = Math.max(startLine - visibleLines				+ electricScroll + 1,firstLine); 			firstLine = Math.min(endLine /* + visibleLines */				- electricScroll,firstLine);			changed = true;		}		else if(virtualCaretLine < _firstLine)		{			firstLine = Math.max(0,virtualCaretLine - electricScroll);			changed = true;		}		else if(virtualCaretLine >= _lastLine)		{			firstLine = (virtualCaretLine - visibleLines)				+ electricScroll + 1;			if(firstLine >= getVirtualLineCount() - visibleLines)				firstLine = getVirtualLineCount() - visibleLines;			changed = true;		}		int x = offsetToX(caretLine,offset);		int width = painter.getFontMetrics().charWidth('w');		if(x < 0)		{			horizontalOffset = Math.min(0,horizontalOffset				- x + width + 5);			changed = true;		}		else if(x >= painter.getWidth() - width - 5)		{			horizontalOffset = horizontalOffset +				(painter.getWidth() - x) - width - 5;			changed = true;		}		if(changed)		{			if(firstLine < 0)				firstLine = 0;			physFirstLine = buffer.virtualToPhysical(firstLine);			updateScrollBars();			painter.repaint();			gutter.repaint();			view.synchroScrollVertical(this,firstLine);			view.synchroScrollHorizontal(this,horizontalOffset);			// fire events for both a horizontal and vertical scroll			fireScrollEvent(true);			fireScrollEvent(false);		}	}