11using System ;
22using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Text ;
35using CommunityToolkit . Mvvm . ComponentModel ;
46using LLCOM . Services ;
7+ using Wcwidth ;
58
69namespace LLCOM . Models ;
710
@@ -22,6 +25,166 @@ private void TerminalChanged()
2225 TerminalChangedEvent ? . Invoke ( this , GetShowLines ( ) ) ;
2326 }
2427
28+ //用于存放终端数据的缓存
29+ private readonly List < List < TerminalBlock > > _cacheLines = [ ] ;
30+
31+ //当前光标位置
32+ //X从0开始,最大可到达窗口宽度(再增加就需要换行了)
33+ //Y从0开始,最大可到达窗口高度-1
34+ private int _positionX = 0 ;
35+ private int _positionY = 0 ;
36+
37+ //当前的颜色、字体等信息,存到TerminalBlock中
38+ private TerminalBlock _currentState = new ( String . Empty ) ;
39+
40+ //MaxCacheLines表示终端缓存的行数,超过这个行数后会删除最上面的行
41+ private readonly int _maxCacheLines = Utils . Setting . TerminalBufferLines ;
42+
43+ //可视范围内的宽高
44+ private int _windowWidth ;
45+ private int _windowHeight ;
46+
47+ //添加新的一行上去
48+ private void AddLine ( )
49+ {
50+ //添加行
51+ _cacheLines . Add ( [ ] ) ;
52+ //如果超过了最大行数,删除最上面的行
53+ if ( _cacheLines . Count > _maxCacheLines )
54+ _cacheLines . RemoveAt ( 0 ) ;
55+ if ( _currentLine != 0 )
56+ {
57+ _currentLine -- ;
58+ //如果当前行数超过了最大行数,设置为最大行数
59+ if ( _currentLine > _cacheLines . Count - _windowHeight )
60+ _currentLine = _cacheLines . Count - _windowHeight ;
61+ if ( _currentLine < 0 ) _currentLine = 0 ;
62+ }
63+ }
64+
65+ /// <summary>
66+ /// 基于当前光标,往后追加文本
67+ /// 文本不得包含不可见字符
68+ /// </summary>
69+ /// <param name="text">待添加的文本</param>
70+ public void AddText ( char [ ] texts ) //TODO)) 保持private
71+ {
72+ //防止没有设置窗口大小的时候就添加数据
73+ if ( _windowWidth == 0 || _windowHeight == 0 )
74+ return ;
75+
76+ var chars = texts [ ..] ;
77+ while ( chars . Length > 0 )
78+ {
79+ //当前光标位置后还有多少个字符的空间
80+ var space = _windowWidth - _positionX ;
81+ //剩余空间不足,添加新行
82+ if ( space <= 0 )
83+ {
84+ _positionX = 0 ;
85+ _positionY ++ ; //超过高度后面再管
86+ space = _windowWidth ;
87+ }
88+ //记录一下修改前的X光标位置
89+ var oldX = _positionX ;
90+
91+ //放置文本
92+ var sb = new StringBuilder ( ) ;
93+ while ( space > 0 && chars . Length > 0 )
94+ {
95+ //获取实际的字符宽度
96+ var length = UnicodeCalculator . GetWidth ( chars [ 0 ] ) ;
97+ //挖去可用空间
98+ space -= length ;
99+ if ( space < 0 ) //剩余空间不足,别添加了
100+ break ;
101+ //添加字符
102+ sb . Append ( chars [ 0 ] ) ;
103+ //去除掉已经添加的字符
104+ chars = chars [ 1 ..] ;
105+ //光标位置往后挪动
106+ _positionX += length ;
107+ }
108+ //添加文本
109+ var text = sb . ToString ( ) ;
110+ var line = _currentState . MakeNew ( text ) ;
111+
112+ //这一行数据要修改
113+ List < TerminalBlock > needChangeLine ;
114+
115+ //超过了最大高度,说明要新开一行
116+ if ( _positionY >= _windowHeight )
117+ {
118+ _positionY = _windowHeight - 1 ;
119+ AddLine ( ) ;
120+ needChangeLine = _cacheLines [ ^ 1 ] ;
121+ }
122+ //当前缓存的行数还没有达到显示行高,也开新行
123+ else if ( _cacheLines . Count - 1 < _positionY )
124+ {
125+ var needLineCount = _positionY - _cacheLines . Count + 1 ;
126+ for ( int i = 0 ; i < needLineCount ; i ++ )
127+ AddLine ( ) ;
128+ needChangeLine = _cacheLines [ ^ 1 ] ;
129+ }
130+ //不是新行,需要更改当前行的数据
131+ else
132+ {
133+ //计算开始行下标的偏移量
134+ var lineStartOffset = _cacheLines . Count - _windowHeight ;
135+ if ( lineStartOffset < 0 )
136+ lineStartOffset = 0 ;
137+ //使用当前行
138+ needChangeLine = _cacheLines [ _positionY + lineStartOffset ] ;
139+ }
140+
141+ var allLength = needChangeLine . Sum ( l => l . Length ) ;
142+ //光标没有重叠,说明可以直接添加到当前行
143+ if ( oldX >= allLength )
144+ {
145+ //看有没有缺的空间,有的话用空格补齐
146+ if ( oldX > allLength )
147+ needChangeLine . Add ( new ( new ( ' ' , oldX - allLength ) ) ) ;
148+ needChangeLine . Add ( line ) ;
149+ }
150+ else
151+ {
152+ //TODO)) 这里需要处理光标重叠的情况
153+ // //查找一下看开始的位置是重叠到哪个元素了
154+ // var hitIndex = 0;
155+ // var hitLength = 0;
156+ // foreach (var block in oldLine)
157+ // {
158+ // if (hitLength + block.Length > oldX)
159+ // break;
160+ // hitLength += block.Length;
161+ // hitIndex++;
162+ // }
163+ // //查找看看结束的位置是重叠到哪个元素了
164+ // var endIndex = hitIndex;
165+ // var endLength = hitLength;
166+ // for(int i = hitIndex; i < oldLine.Count; i++)
167+ // {
168+ // if (endLength + oldLine[i].Length > _positionX)
169+ // break;
170+ // endLength += oldLine[i].Length;
171+ // endIndex++;
172+ // }
173+
174+ }
175+
176+ //优化当前这一行数据块
177+ TerminalBlock . OptimizeBlocks ( needChangeLine ) ;
178+ }
179+ }
180+
181+ //TODO)) 仅用于测试
182+ public void ChangePosition ( int x , int y )
183+ {
184+ _positionX = x ;
185+ _positionY = y ;
186+ }
187+
25188 /// <summary>
26189 /// 获取可以显示的行数据
27190 /// </summary>
@@ -48,15 +211,22 @@ public List<List<TerminalBlock>> GetShowLines()
48211 cacheLines . Add ( line ) ;
49212 }
50213
214+ //如果行数不够,补齐空行
215+ for ( int i = cacheLines . Count ; i < _windowHeight ; i ++ )
216+ {
217+ //添加空行
218+ cacheLines . Add ( [ ] ) ;
219+ }
220+ //把当前光标位置背景和前景色反色处理
221+ var posY = _positionY ;
222+ if ( posY < _cacheLines . Count )
223+ {
224+ //TODO)) 这里需要处理光标位置
225+ }
226+
51227 return cacheLines ;
52228 }
53229
54- //MaxCacheLines表示终端缓存的行数,超过这个行数后会删除最上面的行
55- private readonly int _maxCacheLines = Utils . Setting . TerminalBufferLines ;
56-
57- //可视范围内的宽高
58- private int _windowWidth ;
59- private int _windowHeight ;
60230 //窗口大小变化
61231 public void ChangeWindowSize ( int width , int height )
62232 {
@@ -65,9 +235,6 @@ public void ChangeWindowSize(int width, int height)
65235 TerminalChanged ( ) ;
66236 }
67237
68- //用于存放终端数据的缓存
69- private readonly List < List < TerminalBlock > > _cacheLines = new ( ) ;
70-
71238 //当前所在的行数相比较于终端最底部的行数,0表示在最底部,其余数字表示向上挪动的行数
72239 private int _currentLine = 0 ;
73240
@@ -102,25 +269,4 @@ public void ScrollBarChanged(double value)
102269 if ( lastCurrentLine != _currentLine )
103270 TerminalChanged ( ) ;
104271 }
105-
106-
107- //TODO)) 仅供测试使用
108- public void AddLine ( List < TerminalBlock > line )
109- {
110- //添加行
111- _cacheLines . Add ( line ) ;
112- //如果超过了最大行数,删除最上面的行
113- if ( _cacheLines . Count > _maxCacheLines )
114- _cacheLines . RemoveAt ( 0 ) ;
115- if ( _currentLine != 0 )
116- {
117- _currentLine -- ;
118- //如果当前行数超过了最大行数,设置为最大行数
119- if ( _currentLine > _cacheLines . Count - _windowHeight )
120- _currentLine = _cacheLines . Count - _windowHeight ;
121- }
122-
123- //更新数据
124- TerminalChanged ( ) ;
125- }
126272}
0 commit comments