예제 #1
0
 public void OnPromptLine(GLine line, string prompt, string command)
 {
     _isPrompt = true;
     _lastLine = line;
     _promptText = prompt;
     _commandText = command;
 }
예제 #2
0
        /// <summary>
        /// Clone this instance that text attributes in the specified range are inverted.
        /// </summary>
        /// <param name="from">start column index of the range. (inclusive)</param>
        /// <param name="to">end column index of the range. (exclusive)</param>
        /// <returns>new instance</returns>
        internal GLine CreateInvertedClone(int from, int to) {
            ExpandBuffer(Math.Max(from + 1, to)); //激しくリサイズしたときなどにこの条件が満たせないことがある
            Debug.Assert(from >= 0 && from < _text.Length);
            if (from < _text.Length && _text[from] == WIDECHAR_PAD)
                from--;
            if (to < _text.Length && _text[to] == WIDECHAR_PAD)
                to++;

            const int PHASE_LEFT = 0;
            const int PHASE_MIDDLE = 1;
            const int PHASE_RIGHT = 2;

            int phase = PHASE_LEFT;
            int inverseIndex = from;

            GWord first = null;
            GWord last = null;

            for (GWord word = _firstWord; word != null; word = word.Next) {
                TextDecoration originalDecoration = word.Decoration;
                if (originalDecoration == null)
                    originalDecoration = TextDecoration.Default;

                int wordStart = word.Offset;
                int wordEnd = GetNextOffset(word);

                do {
                    GWord newWord;

                    if (phase == PHASE_RIGHT || inverseIndex < wordStart || wordEnd <= inverseIndex) {
                        TextDecoration newDec = (phase == PHASE_MIDDLE) ? originalDecoration.GetInvertedCopy() : originalDecoration;
                        newWord = new GWord(newDec, wordStart, word.CharGroup);
                        wordStart = wordEnd;
                    }
                    else {
                        TextDecoration leftDec = (phase == PHASE_LEFT) ? originalDecoration : originalDecoration.GetInvertedCopy();

                        if (wordStart < inverseIndex)
                            newWord = new GWord(leftDec, wordStart, word.CharGroup);
                        else
                            newWord = null;

                        wordStart = inverseIndex;

                        // update phase
                        if (phase == PHASE_LEFT) {
                            phase = PHASE_MIDDLE;
                            inverseIndex = to;
                        }
                        else if (phase == PHASE_MIDDLE) {
                            phase = PHASE_RIGHT;
                        }
                    }

                    // append new GWord to the list.
                    if (newWord != null) {
                        if (last == null)
                            first = newWord;
                        else
                            last.Next = newWord;

                        last = newWord;
                    }
                } while (wordStart < wordEnd);
            }

            GLine ret = new GLine((char[])_text.Clone(), _displayLength, first);
            ret.ID = _id;
            ret.EOLType = _eolType;

            return ret;
        }
예제 #3
0
        /// <summary>
        /// <ja>
        /// データをエクスポートします。
        /// </ja>
        /// <en>
        /// Export the data.
        /// </en>
        /// </summary>
        /// <returns><ja>エクスポートされたGLineオブジェクト</ja><en>Exported GLine object</en></returns>
        public GLine Export() {
            GWord firstWord;
            GWord lastWord;

            CharAttr firstAttr = _attrs[0];
            if (firstAttr.Decoration == null)
                firstAttr.Decoration = TextDecoration.Default;
            firstWord = lastWord = new GWord(firstAttr.Decoration, 0, firstAttr.CharGroup);

            int limit = _text.Length;
            int offset;
            if (_text[0] == '\0') {
                offset = 0;
            }
            else {
                CharAttr prevAttr = firstAttr;
                for (offset = 1; offset < limit; offset++) {
                    char ch = _text[offset];
                    if (ch == '\0')
                        break;
                    else if (ch == GLine.WIDECHAR_PAD)
                        continue;

                    CharAttr attr = _attrs[offset];
                    if (attr.Decoration != prevAttr.Decoration || attr.CharGroup != prevAttr.CharGroup) {
                        if (attr.Decoration == null)
                            attr.Decoration = TextDecoration.Default;
                        GWord w = new GWord(attr.Decoration, offset, attr.CharGroup);
                        lastWord.Next = w;
                        lastWord = w;
                        prevAttr = attr;
                    }
                }
            }

            GLine line = new GLine((char[])_text.Clone(), offset, firstWord);
            line.EOLType = _eolType;
            return line;
        }
예제 #4
0
        //TODO �ȉ��Q���\�b�h��ID�����e�i���X��ʓr�s�����Ƃ�O��ɂ��Ă���B
        protected void InsertBefore(GLine pos, GLine line)
        {
            if (pos.PrevLine != null)
                pos.PrevLine.NextLine = line;

            line.PrevLine = pos.PrevLine;
            line.NextLine = pos;

            pos.PrevLine = line;

            if (pos == _firstLine)
                _firstLine = line;
            _size++;
            _invalidatedRegion.InvalidatedAll = true;
        }
예제 #5
0
 //TODO �h�L�������g���ł����Ȃ�Ƃ���ł͒x���Ȃ肻��
 protected GLine FindLineByHint(int index, GLine hintLine)
 {
     int h = hintLine.ID;
     GLine l = hintLine;
     if (index >= h) {
         for (int i = h; i < index; i++) {
             l = l.NextLine;
             if (l == null) {
                 FindLineByHintFailed(index, hintLine);
                 l = hintLine;
                 break;
             }
         }
     }
     else {
         for (int i = h; i > index; i--) {
             l = l.PrevLine;
             if (l == null) {
                 FindLineByHintFailed(index, hintLine);
                 l = hintLine;
                 break;
             }
         }
     }
     return l;
 }
예제 #6
0
 //�����ɒlj�
 public virtual void AddLine(GLine line)
 {
     if (_firstLine == null) { //�󂾂���
         _firstLine = line;
         _lastLine = line;
         _size = 1;
         line.ID = 0;
         _invalidatedRegion.InvalidateLine(0);
     }
     else { //�ʏ�̒lj�
         Debug.Assert(_lastLine.NextLine == null);
         int lastID = _lastLine.ID;
         _lastLine.NextLine = line;
         line.PrevLine = _lastLine;
         _lastLine = line;
         line.ID = lastID + 1;
         _size++;
         _invalidatedRegion.InvalidateLine(lastID + 1);
     }
 }
예제 #7
0
        public void ReplaceCurrentLine(GLine line) {
#if DEBUG
            Replace(_currentLine, line);
#else
            if (_currentLine != null) //クラッシュレポートをみると、何かの拍子にnullになっていたとしか思えない
                Replace(_currentLine, line);
#endif
        }
예제 #8
0
        public void RemoveAfter(int from) {
            GLine delete = FindLineOrNullClipTop(from);
            if (delete == null)
                return;

            GLine remain = delete.PrevLine;
            delete.PrevLine = null;
            if (remain == null) {
                Clear();
            }
            else {
                remain.NextLine = null;
                _lastLine = remain;

                while (delete != null) {
                    _size--;
                    if (delete == _topLine)
                        _topLine = remain;
                    if (delete == _currentLine)
                        _currentLine = remain;
                    delete = delete.NextLine;
                }
            }

            _invalidatedRegion.InvalidatedAll = true;
        }
예제 #9
0
        internal void ScrollUp(int from, int to)
        {
            GLine top = FindLineOrEdge(from);
            GLine bottom = FindLineOrEdge(to);
            if (top == null || bottom == null)
                return; //�G���[�n���h�����O��FindLine�̒��ŁB�����ł̓N���b�V����������s��
            int bottom_id = bottom.ID;
            int topline_id = _topLine.ID;
            GLine nextbottom = bottom.NextLine;

            if (from == to) {
                _currentLine = top;
                _currentLine.Clear();
            }
            else {
                Remove(bottom);
                _currentLine = new GLine(_width);

                InsertBefore(top, _currentLine);
                GLine c = _currentLine;
                do {
                    c.ID = from++;
                    c = c.NextLine;
                } while (c != nextbottom);
                Debug.Assert(nextbottom == null || nextbottom.ID == from);
            }
            /*
            //id maintainance
            GLine c = newbottom;
            GLine end = _currentLine.PrevLine;
            while(c != end) {
                c.ID = bottom_id--;
                c = c.PrevLine;
            }
            */

            //!!���̂Q�s��xterm�����Ă���Ԃɔ������ďC���B VT100�ł͉����̕K�v�������Ă����Ȃ����͂��Ȃ̂Ō�Œ��ׂ邱��
            //if(_scrollingTop<=_topLine.ID && _topLine.ID<=_scrollingBottom)
            //	_topLine = _currentLine;
            while (topline_id < _topLine.ID)
                _topLine = _topLine.PrevLine;

            _invalidatedRegion.InvalidatedAll = true;
        }
예제 #10
0
 public void ReplaceCurrentLine(GLine line)
 {
     #if DEBUG
     Replace(_currentLine, line);
     #else
     if (_currentLine != null) //�N���b�V�����|�[�g��݂�ƁA�����̔��q��null�ɂȂ��Ă����Ƃ����v���Ȃ�
         Replace(_currentLine, line);
     #endif
 }
예제 #11
0
        //�Đڑ��p�Ɍ��݃h�L�������g�̑O�ɑ}��
        public void InsertBefore(TerminalDocument olddoc, int paneheight)
        {
            lock (this) {
                GLine c = olddoc.LastLine;
                int offset = _currentLine.ID - _topLine.ID;
                bool flag = false;
                while (c != null) {
                    if (flag || c.DisplayLength == 0) {
                        flag = true;
                        GLine nl = c.Clone();
                        nl.ID = _firstLine.ID - 1;
                        InsertBefore(_firstLine, nl); //�ŏ��ɋ�łȂ��s������Έȍ~�͑S���}��
                        offset++;
                    }
                    c = c.PrevLine;
                }

                //ID�����ɂȂ�̂͂�����ƕ|���̂ŏC��
                if (_firstLine.ID < 0) {
                    int t = -_firstLine.ID;
                    c = _firstLine;
                    while (c != null) {
                        c.ID += t;
                        c = c.NextLine;
                    }
                }

                _topLine = FindLineOrEdge(_currentLine.ID - Math.Min(offset, paneheight));
                //Dump("insert doc");
            }
        }
예제 #12
0
 public void SetFirstLine(int id)
 {
     _firstLine = FindLineOrEdge(id);
 }
예제 #13
0
        private void AppendTrim(StringBuilder bld, GLine line, int pos, int length)
        {
            Debug.Assert(pos >= 0);
            if (line.IsRightSideOfZenkaku(pos)) { //���{�ꕶ���̉E�[����̂Ƃ��͊g�傷��
                pos--;
                length++;
            }

            line.WriteTo(
                delegate(char[] buff, int len) {
                    bld.Append(buff, 0, len);
                },
                pos, length);
        }
예제 #14
0
        public bool StartSelection(GLine line, int position, RangeType type, int x, int y)
        {
            Debug.Assert(position >= 0);
            //���{�ꕶ���̉E������̑I��͍����ɏC��
            line.ExpandBuffer(position + 1);
            if (line.IsRightSideOfZenkaku(position))
                position--;

            //_disabledTemporary = false;
            _pivotType = type;
            _forwardPivot.Line = line.ID;
            _backwardPivot.Line = line.ID;
            _forwardDestination.Line = line.ID;
            _forwardDestination.Column = position;
            _backwardDestination.Line = line.ID;
            _backwardDestination.Column = position;
            switch (type) {
                case RangeType.Char:
                    _forwardPivot.Column = position;
                    _backwardPivot.Column = position;
                    break;
                case RangeType.Word:
                    _forwardPivot.Column = line.FindPrevWordBreak(position) + 1;
                    _backwardPivot.Column = line.FindNextWordBreak(position);
                    break;
                case RangeType.Line:
                    _forwardPivot.Column = 0;
                    _backwardPivot.Column = line.DisplayLength;
                    break;
            }
            _state = SelectionState.Pivot;
            _startX = x;
            _startY = y;
            FireSelectionStarted();
            return true;
        }
예제 #15
0
        public bool ExpandTo(GLine line, int position, RangeType type)
        {
            line.ExpandBuffer(position + 1);
            //_disabledTemporary = false;
            _state = SelectionState.Expansion;

            _forwardDestination.Line = line.ID;
            _backwardDestination.Line = line.ID;
            //Debug.WriteLine(String.Format("ExpandTo Line{0} Position{1}", line.ID, position));
            switch (type) {
                case RangeType.Char:
                    _forwardDestination.Column = position;
                    _backwardDestination.Column = position;
                    break;
                case RangeType.Word:
                    _forwardDestination.Column = line.FindPrevWordBreak(position) + 1;
                    _backwardDestination.Column = line.FindNextWordBreak(position);
                    break;
                case RangeType.Line:
                    _forwardDestination.Column = 0;
                    _backwardDestination.Column = line.DisplayLength;
                    break;
            }

            return true;
        }
예제 #16
0
 public void StartCommand(AbstractTerminal terminal, string command_text, GLine prompt_line)
 {
 }
예제 #17
0
        /// 最後のremain行以前を削除する
        public int DiscardOldLines(int remain) {
            int delete_count = _size - remain;
            if (delete_count <= 0)
                return 0;

            GLine newfirst = _firstLine;
            for (int i = 0; i < delete_count; i++)
                newfirst = newfirst.NextLine;

            //新しい先頭を決める
            _firstLine = newfirst;
            newfirst.PrevLine.NextLine = null;
            newfirst.PrevLine = null;
            _size -= delete_count;
            Debug.Assert(_size == remain);


            if (_topLine.ID < _firstLine.ID)
                _topLine = _firstLine;
            if (_currentLine.ID < _firstLine.ID) {
                _currentLine = _firstLine;
                _caretColumn = 0;
            }

            return delete_count;
        }
예제 #18
0
 public void StartCommand(AbstractTerminal terminal, string command_text, GLine prompt_line)
 {
     _executingCommand = command_text;
     _terminal = terminal;
 }
예제 #19
0
        //再接続用に現在ドキュメントの前に挿入
        public void InsertBefore(TerminalDocument olddoc, int paneheight) {
            lock (this) {
                GLine c = olddoc.LastLine;
                int offset = _currentLine.ID - _topLine.ID;
                bool flag = false;
                while (c != null) {
                    if (flag || c.DisplayLength == 0) {
                        flag = true;
                        GLine nl = c.Clone();
                        nl.ID = _firstLine.ID - 1;
                        InsertBefore(_firstLine, nl); //最初に空でない行があれば以降は全部挿入
                        offset++;
                    }
                    c = c.PrevLine;
                }

                //IDが負になるのはちょっと怖いので修正
                if (_firstLine.ID < 0) {
                    int t = -_firstLine.ID;
                    c = _firstLine;
                    while (c != null) {
                        c.ID += t;
                        c = c.NextLine;
                    }
                }

                _topLine = FindLineOrEdge(_currentLine.ID - Math.Min(offset, paneheight));
                //Dump("insert doc");
            }
        }
예제 #20
0
        public void OnPromptLine(GLine line, string prompt, string command)
        {
            _lastPromptLine = line;
            _lastCommand = command;

            Debug.WriteLineIf(DebugOpt.CommandPopup, "OnPromptLine " + _state.ToString() + ";" + command);
            if (_currentProcessor != null && _state == State.Fetch && command.Trim().Length == 0) {
                ProcessCommandResult(line.ID - 1);
                _state = State.Prompt;
            }
            else if (_state != State.Fetch)
                _state = State.Prompt;
        }
예제 #21
0
파일: GLine.cs 프로젝트: VirusFree/Poderosa
        /// �����Ɠ�����e�ŏ���������Bline�̓�e�͔j�󂳂�Ȃ��B
        /// ������null�̂Ƃ��͈����Ȃ��̃R���X�g���N�^�Ɠ������ʂɂȂ�B
        /// <summary>
        /// <ja>
        /// �����Ɠ�����e�ŏ��������܂��B
        /// </ja>
        /// <en>
        /// Initialize same as argument.
        /// </en>
        /// </summary>
        /// <param name="cc">
        /// <ja>
        /// �ݒ肷��L�����b�g�ʒu
        /// </ja>
        /// <en>
        /// The caret position to set.
        /// </en>
        /// </param>
        /// <param name="line">
        /// <ja>�R�s�[���ƂȂ�GLine�I�u�W�F�N�g</ja>
        /// <en>GLine object that becomes copy origin</en>
        /// </param>
        /// <remarks>
        /// <ja>
        /// <paramref name="line"/>��null�̂Ƃ��ɂ́A�����Ȃ��̃R���X�g���N�^�Ɠ������ʂɂȂ�܂��B
        /// </ja>
        /// <en>
        /// The same results with the constructor who doesn't have the argument when <paramref name="line"/> is null. 
        /// </en>
        /// </remarks>
        public void Load(GLine line, int cc)
        {
            if (line == null) { //���ꂪnull�ɂȂ��Ă���Ƃ����v���Ȃ��N���b�V�����|�[�g���������B�{���͂Ȃ��͂��Ȃ񂾂�...
                Clear(80);
                return;
            }

            Clear(line.Length);
            GWord w = line.FirstWord;
            _text = line.DuplicateBuffer(_text);

            int n = 0;
            while (w != null) {
                int nextoffset = line.GetNextOffset(w);
                while (n < nextoffset) {
                    _attrs[n++] = new CharAttr(w.Decoration, w.CharGroup);
                }
                w = w.Next;
            }

            _eolType = line.EOLType;
            ExpandBuffer(cc + 1);
            this.CaretColumn = cc; //' '�Ŗ��߂邱�Ƃ����̂Ńv���p�e�B�Z�b�g��g��
        }
예제 #22
0
        internal void ScrollUp(int from, int to) {
            GLine top = FindLineOrEdge(from);
            GLine bottom = FindLineOrEdge(to);
            if (top == null || bottom == null)
                return; //エラーハンドリングはFindLineの中で。ここではクラッシュ回避だけを行う
            int bottom_id = bottom.ID;
            int topline_id = _topLine.ID;
            GLine nextbottom = bottom.NextLine;

            if (from == to) {
                _currentLine = top;
                _currentLine.Clear();
            }
            else {
                Remove(bottom);
                _currentLine = new GLine(_width);

                InsertBefore(top, _currentLine);
                GLine c = _currentLine;
                do {
                    c.ID = from++;
                    c = c.NextLine;
                } while (c != nextbottom);
                Debug.Assert(nextbottom == null || nextbottom.ID == from);
            }
            /*
            //id maintainance
            GLine c = newbottom;
            GLine end = _currentLine.PrevLine;
            while(c != end) {
                c.ID = bottom_id--;
                c = c.PrevLine;
            }
            */

            //!!次の2行はxtermをやっている間に発見して修正。 VT100では何かの必要があってこうなったはずなので後で調べること
            //if(_scrollingTop<=_topLine.ID && _topLine.ID<=_scrollingBottom)
            //	_topLine = _currentLine;
            while (topline_id < _topLine.ID)
                _topLine = _topLine.PrevLine;


            _invalidatedRegion.InvalidatedAll = true;
        }
예제 #23
0
 public void SetFirstLine(int id)
 {
     _firstLine = FindLineOrEdge(id);
 }
예제 #24
0
        internal void ScrollDown(int from, int to) {
            GLine top = FindLineOrEdge(from);
            GLine bottom = FindLineOrEdge(to);
            int top_id = top.ID;
            GLine newtop = top.NextLine;

            if (from == to) {
                _currentLine = top;
                _currentLine.Clear();
            }
            else {
                Remove(top); //_topLineの調整は必要ならここで行われる
                _currentLine = new GLine(_width);
                InsertAfter(bottom, _currentLine);

                //id maintainance
                GLine c = newtop;
                GLine end = _currentLine.NextLine;
                while (c != end) {
                    c.ID = top_id++;
                    c = c.NextLine;
                }
            }

            _invalidatedRegion.InvalidatedAll = true;
        }
예제 #25
0
 //FindLineByHint�͂��΂��Ύ��s����̂Ńf�o�b�O�p�Ɍ��ݏ�Ԃ�_���v
 protected void FindLineByHintFailed(int index, GLine hintLine)
 {
     #if DEBUG
     Debug.WriteLine(String.Format("FindLine {0}, hint_id={1}", index, hintLine.ID));
     Debugger.Break();
     #endif
 }
예제 #26
0
        public void Replace(GLine target, GLine newline) {
            newline.NextLine = target.NextLine;
            newline.PrevLine = target.PrevLine;
            if (target.NextLine != null)
                target.NextLine.PrevLine = newline;
            if (target.PrevLine != null)
                target.PrevLine.NextLine = newline;

            if (target == _firstLine)
                _firstLine = newline;
            if (target == _lastLine)
                _lastLine = newline;
            if (target == _topLine)
                _topLine = newline;
            if (target == _currentLine)
                _currentLine = newline;

            newline.ID = target.ID;
            _invalidatedRegion.InvalidateLine(newline.ID);
        }
예제 #27
0
 public virtual void AssertValid(GLine line, int count)
 {
     GLine next = line.NextLine;
     while (next != null) {
         Debug.Assert(line.ID + 1 == next.ID);
         Debug.Assert(line == next.PrevLine);
         line = next;
         next = next.NextLine;
     }
 }
예제 #28
0
 //末尾に追加する
 public override void AddLine(GLine line) {
     base.AddLine(line);
     if (_size == 1) {
         _currentLine = line;
         _topLine = line;
     }
 }
예제 #29
0
 public GLine Clone() {
     GLine nl = new GLine((char[])_text.Clone(), _displayLength, _firstWord.DeepClone());
     nl._eolType = _eolType;
     nl._id = _id;
     return nl;
 }
예제 #30
0
        public void Remove(GLine line) {
            if (_size <= 1) {
                Clear();
                return;
            }

            if (line.PrevLine != null) {
                line.PrevLine.NextLine = line.NextLine;
            }
            if (line.NextLine != null) {
                line.NextLine.PrevLine = line.PrevLine;
            }

            if (line == _firstLine)
                _firstLine = line.NextLine;
            if (line == _lastLine)
                _lastLine = line.PrevLine;
            if (line == _topLine) {
                _topLine = line.NextLine;
            }
            if (line == _currentLine) {
                _currentLine = line.NextLine;
                if (_currentLine == null)
                    _currentLine = _lastLine;
            }

            _size--;
            _invalidatedRegion.InvalidatedAll = true;
        }
예제 #31
0
        /// 引数と同じ内容で初期化する。lineの内容は破壊されない。
        /// 引数がnullのときは引数なしのコンストラクタと同じ結果になる。
        /// <summary>
        /// <ja>
        /// 引数と同じ内容で初期化します。
        /// </ja>
        /// <en>
        /// Initialize same as argument.
        /// </en>
        /// </summary>
        /// <param name="cc">
        /// <ja>
        /// 設定するキャレット位置
        /// </ja>
        /// <en>
        /// The caret position to set.
        /// </en>
        /// </param>
        /// <param name="line">
        /// <ja>コピー元となるGLineオブジェクト</ja>
        /// <en>GLine object that becomes copy origin</en>
        /// </param>
        /// <remarks>
        /// <ja>
        /// <paramref name="line"/>がnullのときには、引数なしのコンストラクタと同じ結果になります。
        /// </ja>
        /// <en>
        /// The same results with the constructor who doesn't have the argument when <paramref name="line"/> is null. 
        /// </en>
        /// </remarks>
        public void Load(GLine line, int cc) {
            if (line == null) { //これがnullになっているとしか思えないクラッシュレポートがあった。本来はないはずなんだが...
                Clear(80);
                return;
            }

            Clear(line.Length);
            GWord w = line.FirstWord;
            _text = line.DuplicateBuffer(_text);

            int n = 0;
            while (w != null) {
                int nextoffset = line.GetNextOffset(w);
                while (n < nextoffset) {
                    _attrs[n++] = new CharAttr(w.Decoration, w.CharGroup);
                }
                w = w.Next;
            }

            _eolType = line.EOLType;
            ExpandBuffer(cc + 1);
            this.CaretColumn = cc; //' 'で埋めることもあるのでプロパティセットを使う
        }
예제 #32
0
        /// <summary>
        /// Clone this instance that text attributes in the specified range are inverted.
        /// </summary>
        /// <param name="from">start column index of the range. (inclusive)</param>
        /// <param name="to">end column index of the range. (exclusive)</param>
        /// <returns>new instance</returns>
        internal GLine CreateInvertedClone(int from, int to)
        {
            ExpandBuffer(Math.Max(from + 1, to)); //激しくリサイズしたときなどにこの条件が満たせないことがある
            Debug.Assert(from >= 0 && from < _text.Length);
            if (from < _text.Length && _text[from] == WIDECHAR_PAD)
            {
                from--;
            }
            if (to < _text.Length && _text[to] == WIDECHAR_PAD)
            {
                to++;
            }

            const int PHASE_LEFT   = 0;
            const int PHASE_MIDDLE = 1;
            const int PHASE_RIGHT  = 2;

            int phase        = PHASE_LEFT;
            int inverseIndex = from;

            GWord first = null;
            GWord last  = null;

            for (GWord word = _firstWord; word != null; word = word.Next)
            {
                TextDecoration originalDecoration = word.Decoration;
                if (originalDecoration == null)
                {
                    originalDecoration = TextDecoration.Default;
                }

                int wordStart = word.Offset;
                int wordEnd   = GetNextOffset(word);

                do
                {
                    GWord newWord;

                    if (phase == PHASE_RIGHT || inverseIndex < wordStart || wordEnd <= inverseIndex)
                    {
                        TextDecoration newDec = (phase == PHASE_MIDDLE) ? originalDecoration.GetInvertedCopy() : originalDecoration;
                        newWord   = new GWord(newDec, wordStart, word.CharGroup);
                        wordStart = wordEnd;
                    }
                    else
                    {
                        TextDecoration leftDec = (phase == PHASE_LEFT) ? originalDecoration : originalDecoration.GetInvertedCopy();

                        if (wordStart < inverseIndex)
                        {
                            newWord = new GWord(leftDec, wordStart, word.CharGroup);
                        }
                        else
                        {
                            newWord = null;
                        }

                        wordStart = inverseIndex;

                        // update phase
                        if (phase == PHASE_LEFT)
                        {
                            phase        = PHASE_MIDDLE;
                            inverseIndex = to;
                        }
                        else if (phase == PHASE_MIDDLE)
                        {
                            phase = PHASE_RIGHT;
                        }
                    }

                    // append new GWord to the list.
                    if (newWord != null)
                    {
                        if (last == null)
                        {
                            first = newWord;
                        }
                        else
                        {
                            last.Next = newWord;
                        }

                        last = newWord;
                    }
                } while (wordStart < wordEnd);
            }

            GLine ret = new GLine((char[])_text.Clone(), _displayLength, first);

            ret.ID      = _id;
            ret.EOLType = _eolType;

            return(ret);
        }