TerminalDocument.cs
上传用户:szltgg
上传日期:2019-05-16
资源大小:604k
文件大小:15k
源码类别:

Telnet服务器

开发平台:

C#

  1. /*
  2. * Copyright (c) 2005 Poderosa Project, All Rights Reserved.
  3. * $Id: TerminalDocument.cs,v 1.2 2005/04/20 08:45:47 okajima Exp $
  4. */
  5. using System;
  6. using System.Collections;
  7. using System.Drawing;
  8. using System.Diagnostics;
  9. using Poderosa;
  10. using Poderosa.Text;
  11. using Poderosa.Communication;
  12. namespace Poderosa.Text
  13. {
  14. /// <summary>
  15. /// 僞乕儈僫儖偲偟偰摦偐偟偰偄傞偲偒偺
  16. /// </summary>
  17. public class TerminalDocument {
  18. private TerminalConnection _connection; //!!偙傟偼暆偲崅偝庢摼偺偨傔偵偺傒昁梫側僷儔儊僞側偺偱TerminalConnection偼傗傝偡偓
  19. private int _caretColumn;
  20. private int _scrollingTop;
  21. private int _scrollingBottom;
  22. //昤夋偺昁梫偺偁傞ID偺斖埻
  23. private int _invalidatedFrom;
  24. private int _invalidatedTo;
  25. private bool _invalidatedAll; //偙傟偑棫偭偰偄傞偲偒偼柍忦審偱慡昤夋丂惓偟偄Invalidate斖埻偺寁嶼偑柺搢側偲偒偼偙傟
  26. private GLine _firstLine;
  27. private GLine _lastLine;
  28. private GLine _currentLine;
  29. private GLine _topLine;
  30. private int _size; //僒僀僘偼_firstLine/lastLine偐傜寁嶼壜擻偩偑傛偔巊偆偺偱僉儍僢僔儏
  31. internal TerminalDocument(TerminalConnection con) {
  32. _connection = con;
  33. Clear();
  34. _scrollingTop = -1;
  35. _scrollingBottom = -1;
  36. }
  37. public int InvalidatedFrom {
  38. get {
  39. return _invalidatedFrom;
  40. }
  41. }
  42. public int InvalidatedTo {
  43. get {
  44. return _invalidatedTo;
  45. }
  46. }
  47. public bool InvalidatedAll {
  48. get {
  49. return _invalidatedAll;
  50. }
  51. }
  52. public void ResetInvalidatedRegion() {
  53. _invalidatedAll = false;
  54. _invalidatedFrom = -1;
  55. _invalidatedTo = -1;
  56. }
  57. public void InvalidateLine(int id) {
  58. if(_invalidatedFrom==-1 || _invalidatedFrom > id) _invalidatedFrom = id;
  59. if(_invalidatedTo==-1   || _invalidatedTo   < id) _invalidatedTo   = id;
  60. }
  61. public void InvalidateAll() {
  62. _invalidatedAll = true;
  63. }
  64. internal void Clear() {
  65. _caretColumn = 0;
  66. _firstLine = null;
  67. _lastLine = null;
  68. _size = 0;
  69. AddLine(new GLine(_connection.TerminalWidth));
  70. }
  71. public int Size {
  72. get {
  73. return _size;
  74. }
  75. }
  76. //枛旜偵捛壛偡傞
  77. internal void AddLine(GLine line) {
  78. if(_firstLine==null) { //嬻偩偭偨
  79. _firstLine = line;
  80. _lastLine = line;
  81. _currentLine = line;
  82. _topLine = line;
  83. _size = 1;
  84. line.ID = 0;
  85. InvalidateLine(0);
  86. }
  87. else { //捠忢偺捛壛
  88. Debug.Assert(_lastLine.NextLine==null);
  89. int lastID = _lastLine.ID;
  90. _lastLine.NextLine = line;
  91. line.PrevLine = _lastLine;
  92. _lastLine = line;
  93. line.ID = lastID+1;
  94. _size++;
  95. InvalidateLine(lastID+1);
  96. }
  97. }
  98. //惍悢僀儞僨僋僗偐傜尒偮偗傞丂CurrentLine偐傜偦偆墦偔側偄埵抲偩傠偆偲偁偨傝傪偮偗傞
  99. public GLine FindLine(int index) {
  100. //current偲top偺嬤偄曽偐傜弴偵傒偰偄偔
  101. int d1 = Math.Abs(index - _currentLine.ID);
  102. int d2 = Math.Abs(index - _topLine.ID);
  103. if(d1<d2)
  104. return FindLineByHint(index, _currentLine);
  105. else
  106. return FindLineByHint(index, _topLine);
  107. }
  108. public GLine FindLineOrNull(int index) {
  109. if(index < _firstLine.ID || index > _lastLine.ID) return null;
  110. else return FindLine(index);
  111. }
  112. public GLine FindLineOrEdge(int index) {
  113. if(index < _firstLine.ID) index = _firstLine.ID;
  114. else if(index > _lastLine.ID)  index = _lastLine.ID;
  115. return FindLine(index);
  116. }
  117. private GLine FindLineByHint(int index, GLine hintLine) {
  118. int h = hintLine.ID;
  119. GLine l = hintLine;
  120. if(index >= h) {
  121. for(int i=h; i<index; i++) {
  122. l = l.NextLine;
  123. if(l==null) FindLineByHintFailed(index, hintLine);
  124. }
  125. }
  126. else {
  127. for(int i=h; i>index; i--) {
  128. l = l.PrevLine;
  129. if(l==null) FindLineByHintFailed(index, hintLine);
  130. }
  131. }
  132. return l;
  133. }
  134. //FindLineByHint偼偟偽偟偽幐攕偡傞偺偱僨僶僢僌梡偵尰嵼忬懺傪僟儞僾
  135. private void FindLineByHintFailed(int index, GLine hintLine) {
  136. #if DEBUG
  137. Dump(String.Format("FindLine {0}, hint_id={1}", index, hintLine.ID));
  138. Debugger.Break();
  139. #endif
  140. GEnv.InterThreadUIService.InvalidDocumentOperation(this, GEnv.Strings.GetString("Message.TerminalDocument.UnexpectedCode"));
  141. }
  142. internal void SetScrollingRegion(int top_offset, int bottom_offset) {
  143. _scrollingTop = TopLineNumber+top_offset;
  144. _scrollingBottom = TopLineNumber+bottom_offset;
  145. //GLine l = FindLine(_scrollingTop);
  146. }
  147. internal void ClearScrollingRegion() {
  148. _scrollingTop = -1;
  149. _scrollingBottom = -1;
  150. }
  151. public void EnsureLine(int id) {
  152. while(id > _lastLine.ID) {
  153. AddLine(new GLine(_connection.TerminalWidth));
  154. }
  155. }
  156. public int CurrentLineNumber {
  157. get {
  158. return _currentLine.ID;
  159. }
  160. set {
  161. if(value < _firstLine.ID) value = _firstLine.ID; //儕僒僀僘帪偺旝柇側僞僀儈儞僌偱晧偵側偭偰偟傑偆偙偲偑偁偭偨傛偆偩
  162. if(value > _lastLine.ID+100) value = _lastLine.ID+100; //嬌抂偵戝偒側抣傪怘傜偭偰巰偸偙偲偑側偄傛偆偵偡傞
  163. while(value > _lastLine.ID) {
  164. AddLine(new GLine(_connection.TerminalWidth));
  165. }
  166. _currentLine = FindLineOrEdge(value); //奜晹偐傜曄側抣偑搉偝傟偨傝丄偁傞偄偼偳偙偐偵僶僌偑偁傞偣偄偱偙偺拞偱僋儔僢僔儏偡傞偙偲偑傑傟偵偁傞傛偆偩丅側偺偱OrEdge僶乕僕儑儞偵偟偰僋儔僢僔儏偼夞旔
  167. AssertValid();
  168. }
  169. }
  170. public int TopLineNumber {
  171. get {
  172. return _topLine.ID;
  173. }
  174. set {
  175. if(_topLine.ID!=value) _invalidatedAll = true;
  176. _topLine = FindLineOrEdge(value); //摨忋偺棟桼偱OrEdge僶乕僕儑儞偵曄峏
  177. AssertValid();
  178. }
  179. }
  180. public int FirstLineNumber {
  181. get {
  182. return _firstLine.ID;
  183. }
  184. }
  185. public int LastLineNumber {
  186. get {
  187. return _lastLine.ID;
  188. }
  189. }
  190. public int CaretColumn {
  191. get {
  192. return _caretColumn;
  193. }
  194. set {
  195. _caretColumn = value;
  196. }
  197. }
  198. public GLine CurrentLine {
  199. get {
  200. return _currentLine;
  201. }
  202. }
  203. public GLine TopLine {
  204. get {
  205. return _topLine;
  206. }
  207. }
  208. public GLine FirstLine {
  209. get {
  210. return _firstLine;
  211. }
  212. }
  213. public GLine LastLine {
  214. get {
  215. return _lastLine;
  216. }
  217. }
  218. public bool CurrentIsLast {
  219. get {
  220. return _currentLine.NextLine==null;
  221. }
  222. }
  223. public int ScrollingTop {
  224. get {
  225. return _scrollingTop;
  226. }
  227. }
  228. public int ScrollingBottom {
  229. get {
  230. return _scrollingBottom;
  231. }
  232. }
  233. internal void LineFeed() {
  234. if(_scrollingTop!=-1 && _currentLine.ID >= _scrollingBottom) { //儘僢僋偝傟偰偄偰壓傑偱峴偭偰偄傞
  235. ScrollDown(); 
  236. }
  237. else {
  238. if(_connection.TerminalHeight>1) { //嬌抂偵崅偝偑側偄偲偒偼偙傟偱曄側抣偵側偭偰偟傑偆偺偱僗僉僢僾
  239. if(_currentLine.ID >= _topLine.ID + _connection.TerminalHeight - 1)
  240. this.TopLineNumber = _currentLine.ID - _connection.TerminalHeight + 2; //偙傟偱師偺CurrentLineNumber++偲崌傢偣偰峴憲傝偵側傞
  241. }
  242. this.CurrentLineNumber++; //偙傟偱僾儘僷僥傿僙僢僩偑側偝傟丄昁梫側傜峴偺捛壛傕偝傟傞丅
  243. }
  244. AssertValid();
  245. //Debug.WriteLine(String.Format("c={0} t={1} f={2} l={3}", _currentLine.ID, _topLine.ID, _firstLine.ID, _lastLine.ID));
  246. }
  247. //僗僋儘乕儖斖埻偺嵟傕壓傪侾峴徚偟丄嵟傕忋偵侾峴捛壛丅尰嵼峴偼偦偺怴婯峴偵側傞丅
  248. internal void ScrollUp() {
  249. if(_scrollingTop!=-1 && _scrollingBottom!=-1)
  250. ScrollUp(_scrollingTop, _scrollingBottom);
  251. else
  252. ScrollUp(TopLineNumber, TopLineNumber + _connection.TerminalHeight - 1);
  253. }
  254. internal void ScrollUp(int from, int to) {
  255. GLine top = FindLineOrEdge(from);
  256. GLine bottom = FindLineOrEdge(to);
  257. if(top==null || bottom==null) return; //僄儔乕僴儞僪儕儞僌偼FindLine偺拞偱丅偙偙偱偼僋儔僢僔儏夞旔偩偗傪峴偆
  258. int bottom_id = bottom.ID;
  259. int topline_id = _topLine.ID;
  260. GLine nextbottom = bottom.NextLine;
  261. if(from==to) {
  262. _currentLine = top;
  263. _currentLine.Clear();
  264. }
  265. else {
  266. Remove(bottom);
  267. _currentLine = new GLine(_connection.TerminalWidth);
  268. InsertBefore(top, _currentLine);
  269. GLine c = _currentLine;
  270. do {
  271. c.ID = from++;
  272. c = c.NextLine;
  273. } while(c!=nextbottom);
  274. Debug.Assert(nextbottom==null || nextbottom.ID==from);
  275. }
  276. /*
  277. //id maintainance
  278. GLine c = newbottom;
  279. GLine end = _currentLine.PrevLine;
  280. while(c != end) {
  281. c.ID = bottom_id--;
  282. c = c.PrevLine;
  283. }
  284. */
  285. //!!師偺俀峴偼xterm傪傗偭偰偄傞娫偵敪尒偟偰廋惓丅 VT100偱偼壗偐偺昁梫偑偁偭偰偙偆側偭偨偼偢側偺偱屻偱挷傋傞偙偲
  286. //if(_scrollingTop<=_topLine.ID && _topLine.ID<=_scrollingBottom)
  287. // _topLine = _currentLine;
  288. while(topline_id<_topLine.ID)
  289. _topLine = _topLine.PrevLine;
  290. AssertValid();
  291. _invalidatedAll = true;
  292. }
  293. //僗僋儘乕儖斖埻偺嵟傕忋傪侾峴徚偟丄嵟傕壓偵侾峴捛壛丅尰嵼峴偼偦偺怴婯峴偵側傞丅
  294. internal void ScrollDown() {
  295. if(_scrollingTop!=-1 && _scrollingBottom!=-1)
  296. ScrollDown(_scrollingTop, _scrollingBottom);
  297. else
  298. ScrollDown(TopLineNumber, TopLineNumber + _connection.TerminalHeight - 1);
  299. }
  300. internal void ScrollDown(int from, int to) {
  301. GLine top = FindLineOrEdge(from);
  302. GLine bottom = FindLineOrEdge(to);
  303. int top_id = top.ID;
  304. GLine newtop = top.NextLine;
  305. if(from==to) {
  306. _currentLine = top;
  307. _currentLine.Clear();
  308. }
  309. else {
  310. Remove(top); //_topLine偺挷惍偼昁梫側傜偙偙偱峴傢傟傞
  311. _currentLine = new GLine(_connection.TerminalWidth);
  312. InsertAfter(bottom, _currentLine);
  313. //id maintainance
  314. GLine c = newtop;
  315. GLine end = _currentLine.NextLine;
  316. while(c != end) {
  317. c.ID = top_id++;
  318. c = c.NextLine;
  319. }
  320. }
  321. AssertValid();
  322. _invalidatedAll = true;
  323. }
  324. internal void Replace(GLine target, GLine newline) {
  325. newline.NextLine = target.NextLine;
  326. newline.PrevLine = target.PrevLine;
  327. if(target.NextLine!=null) target.NextLine.PrevLine = newline;
  328. if(target.PrevLine!=null) target.PrevLine.NextLine = newline;
  329. if(target==_firstLine) _firstLine = newline;
  330. if(target==_lastLine)  _lastLine = newline;
  331. if(target==_topLine)  _topLine  = newline;
  332. if(target==_currentLine) _currentLine = newline;
  333. newline.ID = target.ID;
  334. InvalidateLine(newline.ID);
  335. AssertValid();
  336. }
  337. internal void ReplaceCurrentLine(GLine line) {
  338. #if DEBUG
  339. Replace(_currentLine, line);
  340. AssertValid();
  341. #else
  342. if(_currentLine!=null) //僋儔僢僔儏儗億乕僩傪傒傞偲丄壗偐偺攺巕偵null偵側偭偰偄偨偲偟偐巚偊側偄
  343. Replace(_currentLine, line);
  344. #endif
  345. }
  346. internal void Remove(GLine line) {
  347. if(_size<=1) {
  348. Clear();
  349. return;
  350. }
  351. if(line.PrevLine!=null) {
  352. line.PrevLine.NextLine = line.NextLine;
  353. }
  354. if(line.NextLine!=null) {
  355. line.NextLine.PrevLine = line.PrevLine;
  356. }
  357. if(line==_firstLine) _firstLine = line.NextLine;
  358. if(line==_lastLine)  _lastLine = line.PrevLine;
  359. if(line==_topLine) {
  360. _topLine = line.NextLine;
  361. }
  362. if(line==_currentLine) {
  363. _currentLine = line.NextLine;
  364. if(_currentLine==null) _currentLine = _lastLine;
  365. }
  366. _size--;
  367. _invalidatedAll = true;
  368. }
  369. private void InsertBefore(GLine pos, GLine line) {
  370. if(pos.PrevLine!=null)
  371. pos.PrevLine.NextLine = line;
  372. line.PrevLine = pos.PrevLine;
  373. line.NextLine = pos;
  374. pos.PrevLine = line;
  375. if(pos==_firstLine)  _firstLine = line;
  376. _size++;
  377. _invalidatedAll = true;
  378. }
  379. private void InsertAfter(GLine pos, GLine line) {
  380. if(pos.NextLine!=null)
  381. pos.NextLine.PrevLine = line;
  382. line.NextLine = pos.NextLine;
  383. line.PrevLine = pos;
  384. pos.NextLine = line;
  385. if(pos==_lastLine)  _lastLine = line;
  386. _size++;
  387. _invalidatedAll = true;
  388. }
  389. internal void RemoveAfter(int from) {
  390. if(from > _lastLine.ID) return;
  391. GLine delete = FindLineOrEdge(from);
  392. if(delete==null) return;
  393. GLine remain = delete.PrevLine;
  394. delete.PrevLine = null;
  395. if(remain==null) {
  396. Clear();
  397. }
  398. else {
  399. remain.NextLine = null;
  400. _lastLine = remain;
  401. while(delete!=null) {
  402. _size--;
  403. if(delete==_topLine) _topLine = remain;
  404. if(delete==_currentLine) _currentLine = remain;
  405. delete = delete.NextLine;
  406. }
  407. }
  408. AssertValid();
  409. _invalidatedAll = true;
  410. }
  411. internal void ClearAfter(int from) {
  412. if(from > _lastLine.ID) return;
  413. GLine l = FindLineOrEdge(from);
  414. if(l==null) return;
  415. while(l!=null) {
  416. l.Clear();
  417. l = l.NextLine;
  418. }
  419. AssertValid();
  420. _invalidatedAll = true;
  421. }
  422. internal void ClearAfter(int from, TextDecoration dec) {
  423. if(from > _lastLine.ID) return;
  424. GLine l = FindLineOrEdge(from);
  425. if(l==null) return;
  426. while(l!=null) {
  427. l.Clear(dec);
  428. l = l.NextLine;
  429. }
  430. AssertValid();
  431. _invalidatedAll = true;
  432. }
  433. internal void ClearRange(int from, int to) {
  434. GLine l = FindLineOrEdge(from);
  435. if(l==null) return;
  436. while(l.ID < to) {
  437. l.Clear();
  438. InvalidateLine(l.ID);
  439. l = l.NextLine;
  440. }
  441. AssertValid();
  442. }
  443. internal void ClearRange(int from, int to, TextDecoration dec) {
  444. GLine l = FindLineOrEdge(from);
  445. if(l==null) return;
  446. while(l.ID < to) {
  447. l.Clear(dec);
  448. InvalidateLine(l.ID);
  449. l = l.NextLine;
  450. }
  451. AssertValid();
  452. }
  453. /// <summary>
  454. /// 嵟屻偺remain峴埲慜傪嶍彍偡傞
  455. /// </summary>
  456. internal int DiscardOldLines(int remain) {
  457. int delete_count = _size - remain;
  458. if(delete_count <= 0) return 0;
  459. GLine newfirst = _firstLine;
  460. for(int i=0; i<delete_count; i++)
  461. newfirst = newfirst.NextLine;
  462. //怴偟偄愭摢傪寛傔傞
  463. _firstLine = newfirst;
  464. newfirst.PrevLine.NextLine = null;
  465. newfirst.PrevLine = null;
  466. _size -= delete_count;
  467. Debug.Assert(_size==remain);
  468. AssertValid();
  469. if(_topLine.ID<_firstLine.ID) _topLine=_firstLine;
  470. if(_currentLine.ID<_firstLine.ID) {
  471. _currentLine = _firstLine;
  472. _caretColumn = 0;
  473. }
  474. return delete_count;
  475. }
  476. //嵞愙懕梡偵尰嵼僪僉儏儊儞僩偺慜偵憓擖
  477. public void InsertBefore(TerminalDocument olddoc, int paneheight) {
  478. lock(this) {
  479. GLine c = olddoc.LastLine;
  480. int offset = _currentLine.ID - _topLine.ID;
  481. bool flag = false;
  482. while(c!=null) {
  483. if(flag || c.Text[0]!='') {
  484. flag = true;
  485. GLine nl = c.Clone();
  486. nl.ID = _firstLine.ID-1;
  487. InsertBefore(_firstLine, nl); //嵟弶偵嬻偱側偄峴偑偁傟偽埲崀偼慡晹憓擖
  488. offset++;
  489. }
  490. c = c.PrevLine;
  491. }
  492. //ID偑晧偵側傞偺偼偪傚偭偲晐偄偺偱廋惓
  493. if(_firstLine.ID<0) {
  494. int t = -_firstLine.ID;
  495. c = _firstLine;
  496. while(c!=null) {
  497. c.ID += t;
  498. c = c.NextLine;
  499. }
  500. }
  501. _topLine = FindLineOrEdge(_currentLine.ID - Math.Min(offset, paneheight));
  502. //Dump("insert doc");
  503. }
  504. }
  505. public void Dump(string title) {
  506. Debug.WriteLine("<<<< DEBUG DUMP ["+title+"] >>>>");
  507. Debug.WriteLine(String.Format("[size={0} top={1} current={2} caret={3} first={4} last={5} region={6},{7}]", _size, TopLineNumber, CurrentLineNumber, _caretColumn, FirstLineNumber, LastLineNumber, _scrollingTop, _scrollingBottom));
  508. GLine gl = FindLineOrEdge(TopLineNumber);
  509. int count = 0;
  510. while(gl!=null && count++ < _connection.TerminalHeight) {
  511. Debug.Write(String.Format("{0,3}",gl.ID));
  512. Debug.Write(":");
  513. Debug.Write(GLineManipulator.SafeString(gl.Text));
  514. Debug.Write(":");
  515. Debug.WriteLine(gl.EOLType);
  516. gl = gl.NextLine;
  517. }
  518. }
  519. public virtual void AssertValid() {
  520. #if false
  521. Debug.Assert(_currentLine.ID>=0);
  522. Debug.Assert(_currentLine.ID>=_topLine.ID);
  523. GLine l = _topLine;
  524. GLine n = l.NextLine;
  525. while(n!=null) {
  526. Debug.Assert(l.ID+1==n.ID);
  527. Debug.Assert(l==n.PrevLine);
  528. l = n;
  529. n = n.NextLine;
  530. }
  531. #endif
  532. }
  533. }
  534. }