public string GetText(DPos s, DPos e) { IText buff; if (s.tl == e.tl) { // 一行だけの場合 //text_[s.tl].CopyAt( s.ad, e.ad-s.ad, buf ); //buf[e.ad-s.ad] = L'\0'; buff = text_[s.tl].Text.Substring(s.ad, e.ad - s.ad); } else { buff = new TextBuffer(""); // 先頭行の後ろをコピー //buf += text_[s.tl].CopyToTail( s.ad, buf ); //*buf++ = '\r', *buf++ = '\n'; buff.Append(text_[s.tl].Text.Substring(s.ad).ToString()); buff.Append("\r\n"); // 途中をコピー for (int i = s.tl + 1; i < e.tl; i++) { //buf += text_[i].CopyToTail( 0, buf ); //*buf++ = '\r', *buf++ = '\n'; buff.Append(text_[i].Text.Substring(0).ToString()); buff.Append("\r\n"); } // 終了行の先頭をコピー //buf += text_[e.tl].CopyAt( 0, e.ad, buf ); //*buf = L'\0'; buff.Append(text_[e.tl].Text.Substring(0, e.ad).ToString()); } return(buff.ToString()); }
public ICommand Execute(Document doc) { //DocImpl & di = d.impl(); //// 削除 //unicode* buf; //ulong siz; //DPos s = stt_, e = end_; //bool aa = di.DeletingOperation(s, e, buf, siz); //// イベント発火 //di.Fire_TEXTUPDATE(s, e, s, aa, true); //// 逆操作オブジェクトを返す //return new Insert(s, buf, siz, true); string buf; DPos s = new DPos(stt_); DPos e = new DPos(end_); bool aa = doc.DeletingOperation(ref s, ref e, out buf); //TextUpdate(s, e, s, aa, true); doc.Fire_TEXTUPDATE(s, e, s, aa, true); return(new Insert(s, buf)); }
//TODO wordStartOf internal DPos wordStartOf(DPos dp) { if (dp.ad == 0) { // 行の先頭 return(dp); } else { // 行の途中 //const uchar* f = pl(dp.tl); // ulong s = dp.ad; //while( (f[s]>>5)==0 && 0<=s ) // --s; //return DPos( dp.tl, s ); var f = text_[dp.tl].Text; int s = dp.ad; Util.CharType ctype = Util.getCharType(f[s]); while (0 < s && Util.getCharType(f[s]) == ctype) { --s; } //s++; s = s != 0 ? ++s : s; return(new DPos(dp.tl, s)); } }
public ICommand Execute(Document doc) { //DocImpl & di = d.impl(); //// 削除 //unicode* buf; //ulong siz; //DPos s = stt_, e = end_; //bool aa = di.DeletingOperation(s, e, buf, siz); //// 挿入 //DPos e2; //aa = (di.InsertingOperation(s, buf_, len_, e2) || aa); //// イベント発火 //di.Fire_TEXTUPDATE(s, e, e2, aa, true); //// 逆操作オブジェクトを返す //return new Replace(s, e2, buf, siz, true); string buf; DPos s = new DPos(stt_); DPos e = new DPos(end_); bool aa = doc.DeletingOperation(ref s, ref e, out buf); DPos e2 = new DPos(); aa = (doc.InsertingOperation(ref s, buf_, ref e2) || aa); doc.Fire_TEXTUPDATE(s, e, e2, aa, true); return(new Replace(s, e2, buf)); }
public void ReplaceAllImpl() { // まず、実行する置換を全てここに登録する //doc::MacroCommand mcr; // 置換後文字列 //const wchar_t* ustr = replStr_.ConvToWChar(); //const ulong ulen = my_lstrlenW( ustr ); List <ICommand> mcr = new List <ICommand>(); // 文書の頭から検索 int dif = 0; DPos s = new DPos(0, 0);//s(0,0) DPos b = new DPos(); DPos e = new DPos(); while (FindNextFromImpl(new DPos(s), ref b, ref e)) { if (s.tl != b.tl) { dif = 0; } //s = e; s.tl = e.tl; s.ad = e.ad; // 置換コマンドを登録 b.ad += dif; e.ad += dif; mcr.Add(new Replace(b, e, ReplaceWord)); dif -= e.ad - b.ad - ReplaceWord.Length; int f = dif; } //if( mcr.size() > 0 ){ // // ここで連続置換 // edit.getDoc().Execute( mcr ); // // カーソル移動 // e.ad = b.ad + ulen; // edit.cursor.MoveCur( e, false ); // // 閉じる? // //End( IDOK ); //} if (mcr.Count > 0) { // ここで連続置換 foreach (var cmd in mcr) { //view.GetDocument().Execute(cmd); document.Execute(cmd); } // カーソル移動 e.ad = b.ad + ReplaceWord.Length; //view.cursor.MoveCur(e, false); view.MoveCursor(e); } }
private bool FindPrevFromImpl(DPos s, ref DPos beg, ref DPos end) { Searcher.SearchWord = this.SearchWord; // 1行ずつサーチ //Document d = view.Document(); //IDocument d = view.Document; //for( int mbg=0,med=0; ; s.ad=d.len(--s.tl) ){ for (int mbg = 0, med = 0; ; s.ad = document.GetLength(--s.tl)) { if (Searcher.Search( //d.tl(s.tl).ToString(), d.len(s.tl), s.ad, ref mbg, ref med ) ){ document.GetText(s.tl), document.GetLength(s.tl), s.ad, ref mbg, ref med)) { beg.tl = end.tl = s.tl; beg.ad = mbg; end.ad = med; return(true); // 発見 } if (s.tl == 0) { break; } } return(false); }
// //------------------------------------------------------------------------- // 再描画したい範囲を Invalidate する。 //------------------------------------------------------------------------- private void ReDraw(ReDrawType r, DPos s) { // まずスクロールバーを更新 //UpdateScrollBar(); switch (r) { case ReDrawType.ALL: // 全画面 //::InvalidateRect( hwnd_, NULL, FALSE ); this.Invalidate(false); break; case ReDrawType.LNAREA: // 行番号表示域のみ if (lna() > 0) { Rectangle rc = new Rectangle(0, 0, lna(), bottom()); //::InvalidateRect( hwnd_, &rc, FALSE ); this.Invalidate(rc, false); } break; case ReDrawType.LINE: // 指定した行の後半 case ReDrawType.AFTER: // 指定した行以下全部 DPos st = (s.ad == 0 ? s : doc_.leftOf(s, true)); InvalidateView(st, r == ReDrawType.AFTER); break; } }
public DocumentEventArgs(Document document, DocumentEventType type, DPos s, int len, string value) { this.document = document; this.type = type; this.s = s; this.len = len; this.value = value; }
private void CorrectPos(ref DPos s, ref DPos e) { // 必ずs<=eになるように修正 if (s > e) { int tmp; tmp = s.ad; s.ad = e.ad; e.ad = tmp; tmp = s.tl; s.tl = e.tl; e.tl = tmp; } }
internal ReDrawType TextUpdate_ScrollBar( DPos s, DPos e, DPos e2 ){ int prevUdMax = vScrollBar.Maximum; bool rlScrolled = ReSetScrollInfo(); int vl_dif = (vScrollBar.Maximum - prevUdMax); ReDrawType ans = (vl_dif != 0 || s.tl != e2.tl ? ReDrawType.AFTER : ReDrawType.LINE); if( udScr_tl_ < s.tl ){ // パターン1:現在の画面上端より下で更新された場合 // スクロールしない } else if( udScr_tl_ == s.tl ){ // パターン2:現在の画面上端と同じ行で更新された場合 // 出来るだけ同じ位置を表示し続けようと試みる。 if( vScrollBar.Value >= vln() ){ // パターン2-1:しかしそこはすでにEOFよりも下だ! // しゃーないので一番下の行を表示 vScrollBar.Value = vln() - 1; udScr_tl_ = doc_.tln()-1; udScr_vrl_ = rln(udScr_tl_)-1; ans = ReDrawType.ALL; } else{ // パターン2-2: // スクロール無し while( udScr_vrl_ >= rln(udScr_tl_) ){ udScr_vrl_ -= rln(udScr_tl_); udScr_tl_++; } } } else{ // パターン3:現在の画面上端より上で更新された場合 // 表示内容を変えないように頑張る if( e.tl < udScr_tl_ ){ // パターン3-1:変更範囲の終端も、現在行より上の場合 // 行番号は変わるが表示内容は変わらないで済む vScrollBar.Value += vl_dif; udScr_tl_ += (e2.tl - e.tl); ans = ReDrawType.LNAREA; } else{ // パターン3-2: // どうしよーもないので適当な位置にスクロール ForceScrollTo( e2.tl ); ans = ReDrawType.ALL; } } // どんな再描画をすればよいか返す return (rlScrolled ? ReDrawType.ALL : ans); }
/// <summary> /// 指定した一行のみ折り返しを修正。 /// 昔は再描画範囲の計算のために、表示行数の変化を返していたが、 /// これは上位ルーチン側で vln() を比較すれば済むし、 /// むしろその方が効率的であるため廃止した。 /// </summary> /// <param name="s"></param> /// <returns> /// 2: "折り返しあり" or "この行が横に一番長くなった" /// 1: "この行以外のどこかが最長" /// 0: "さっきまでこの行は最長だったが短くなっちゃった" /// で、上位ルーチンにm_TextCx修正の必要性を伝える。 /// </returns> int ReWrapSingle(DPos s) { // 旧情報保存 WLine wl = wrap_[s.tl]; int oldVRNum = wl.rln(); int oldWidth = wl.width; // 横幅更新 wl.width = CalcLineWidth(doc_.tl(s.tl).ToString(), doc_.len(s.tl)); if (wl.width < cvs_.wrapWidth()) { // 設定した折り返し幅より短い場合は一行で済む。 wl[1] = doc_.len(s.tl); wl.ForceSize(2); } else { // 複数行になる場合 int vr = 1, stt = 0; while (wl[vr] < s.ad) // while( vr行目は変更箇所より手前 ) { stt = wl[vr++]; // stt = 次の行の行頭のアドレス } // 変更箇所以降のみ修正 wl.ForceSize(vr); ModifyWrapInfo(doc_.tl(s.tl).ToString(), doc_.len(s.tl), ref wl, stt); } // 表示行の総数を修正 vlNum_ += (wl.rln() - oldVRNum); // 折り返しなしだと総横幅の更新が必要 //if( cvs_.wrapType() == NOWRAP ) if (cvs_.wrapType == WrapType.NonWrap) { if (textCx_ <= wl.width) { textCx_ = wl.width; return(2); } else if (textCx_ == oldWidth) { return(0); } else { return(1); } } return(2); }
public void GetSelction(out DPos s, out DPos e) { if (cur_.Cur <= cur_.Sel) { s = cur_.Cur; e = cur_.Sel; } else { s = cur_.Sel; e = cur_.Cur; } }
internal bool InsertingOperation(ref DPos s, string text, ref DPos e) { // 位置補正 //DPos cs = s as DPos; CorrectPos(ref s); //int insertIndex = s.ad; e.ad = s.ad; e.tl = s.tl; string[] lines = SplitLine(text); int lineLen = 0; // 一行目… text_[e.tl].Text.Insert(e.ad, lines[0]); //lineLen = lines[0].Length; strinfo.String = lines[0]; lineLen = strinfo.LengthInTextElements; e.ad += lineLen; // 二行目~最終行 if (lines.Count() > 1) { for (int i = 1; i < lines.Count(); i++) { text_.Insert(++e.tl, new Line(lines[i])); //lineLen = lines[i].Length; strinfo.String = lines[i]; lineLen = strinfo.LengthInTextElements; } // 一行目の最後尾に残ってた文字列を最終行へ Line fl = text_[s.tl]; Line ed = text_[e.tl]; int ln = fl.Length - e.ad; if (ln > 0) { //ed.InsertToTail(fl.str() + e.ad, ln); //fl.RemoveToTail(e.ad); ed.Text.Append(fl.Text.Substring(e.ad, fl.Length - e.ad).ToString()); fl.Text.Remove(e.ad); } // 終了位置記録 e.ad = lineLen; } //return ReParse(s.tl, e.tl); return(ReParse(s.ad, s.tl, e.tl)); }
public void ReplaceImpl() { // カーソル位置取得 //VPos stt = new VPos(); //VPos end = new VPos(); //view.cursor.getCurPos( out stt, out end ); DPos stt, end; view.GetSelction(out stt, out end); // 選択範囲先頭から検索 DPos b = new DPos(); DPos e = new DPos(); if (FindNextFromImpl(stt, ref b, ref e)) { if (e == (DPos)end) { //string str = replStr_.ConvToWChar(); //int len = replstr.Length; // 置換 //edit.getDoc().Execute( doc::Replace( // b, e, ustr, ulen //) ); //view.Document.Execute(new Replace(b, e, ReplaceWord)); document.Replace(b, e, ReplaceWord); if (FindNextFromImpl(new DPos(b.tl, b.ad + ReplaceWord.Length), ref b, ref e)) { // 次を選択 //view.cursor.MoveCur( b, false ); //view.cursor.MoveCur( e, true ); view.SetSelction(b, e); return; } } else { // そうでなければとりあえず選択 //view.cursor.MoveCur( b, false ); //view.cursor.MoveCur( e, true ); view.SetSelction(b, e); return; } } // 見つからなかった場合 //NotFound(); }
// void InvalidateView( DPos dp, bool afterall ){ int H = cvs_.getPainter().H(); // 表示域より上での更新 if( dp.tl < udScr_tl_ ){ if( afterall ) //::InvalidateRect( hwnd_, NULL, FALSE ); this.Invalidate(false); return; } // 開始y座標計算 int r=0, yb=-udScr_vrl_; for( int t=udScr_tl_, ybe=cy()/H; t<dp.tl; yb+=rln(t++) ) if( yb >= ybe ) return; for( ; dp.ad>rlend(dp.tl,r); ++r,++yb ); yb = H * Math.Max( yb, -100 ); // 上にはみ出し過ぎないよう調整 if( yb >= cy() ) return; // 1行目を再描画 int rb = (r==0 ? 0 : rlend(dp.tl,r-1)); string text = doc_.tl(dp.tl).Substring(rb).ToString(); //int xb = left() + Math.Max( 0, // //CalcLineWidth(doc_.tl(dp.tl)+rb, dp.ad-rb) -rlScr_.nPos ); // CalcLineWidth(text, dp.ad - rb) - hScrollBar.Value); int xb = left(); if( xb < right() ){ Rectangle rc = new Rectangle(xb, yb, right(), H); this.Invalidate(rc, false); //this.Invalidate(false); } // 残り int ye; yb += H; if( afterall ){ xb=0; ye=cy(); }else{ xb=left(); ye=Math.Min(cy(),yb+(int)(H*(rln(dp.tl)-r-1))); } if( yb < ye ){ Rectangle rc = new Rectangle( xb, yb, right(), ye ); //::InvalidateRect( hwnd_, &rc, FALSE ); this.Invalidate(rc, false); } }
public ICommand Execute(Document doc) { // 挿入 DPos s = new DPos(stt_); //, e; DPos e = new DPos(); bool aa = doc.InsertingOperation(ref s, buf_, ref e); // イベント発火 //doc.Fire_TEXTUPDATE(s, s, e, aa, true); doc.Fire_TEXTUPDATE(s, s, e, aa, true); // 逆操作オブジェクトを返す return(new Delete(s, e)); }
internal DPos rightOf(DPos dp, bool wide) { if (dp.ad == len(dp.tl)) { // 行末だが、ファイルの終わりではない場合 // 一つ後の行の先頭へ if (dp.tl < tln() - 1) { return(new DPos(dp.tl + 1, 0)); } return(dp); } else if (!wide) { // 行の途中で、普通に1文字進む場合 string l = tl(dp.tl).ToString(); // 番兵 0x007f が l の末尾にいるので長さチェックは不要 //if (Util.isHighSurrogate(l[dp.ad]) && Util.isLowSurrogate(l[dp.ad + 1])) // return new DPos(dp.tl, dp.ad + 2); return(new DPos(dp.tl, dp.ad + 1)); } else { //TODO 行の途中で、普通に1単語進む場合 //const uchar* f = pl(dp.tl); //const ulong e = len(dp.tl); //ulong s = dp.ad; //const ulong t = (f[s] >> 5); //s += t; //if (s >= e) // s = e; //else if (t == 7 || t == 0) // while ((f[s] >> 5) == 0 && s < e) // ++s; //return DPos(dp.tl, s); var f = text_[dp.tl].Text; int e = len(dp.tl); int s = dp.ad; Util.CharType ctype = Util.getCharType(f[s]); while (s < e && Util.getCharType(f[s]) == ctype) { ++s; } //s = s != e ? --s : s; return(new DPos(dp.tl, s)); } }
public Tuple <DPos, DPos> GetSelction() { DPos s, e; if (cur_.Cur <= cur_.Sel) { s = new DPos(cur_.Cur.tl, cur_.Cur.ad); e = new DPos(cur_.Sel.tl, cur_.Sel.ad); } else { s = new DPos(cur_.Sel.tl, cur_.Sel.ad); e = new DPos(cur_.Cur.tl, cur_.Cur.ad); } return(new Tuple <DPos, DPos>(s, e)); }
//------------------------------------------------------------------------- // 挿入・削除等の作業用関数群 //------------------------------------------------------------------------- internal int getRangeLength(DPos s, DPos e) { // とりあえず全部足す int ans = 0, tl = s.tl, te = e.tl; for ( ; tl <= te; ++tl) { ans += len(tl); } // 先頭行の分を引く ans -= s.ad; // 最終行の分を引く ans -= len(te) - e.ad; // 改行コード(CRLF)の分を加える ans += (e.tl - s.tl) * 2; // おしまい return(ans); }
public Point GetPointFromDPos(DPos dp) { int x, y; if (dp == this.cur_.Cur) { x = this.cur_.Cur.rx; y = this.cur_.Cur.vl * fnt().H(); } else { VPos vp = new VPos(); this.ConvDPosToVPos(dp, ref vp); x = vp.rx; y = vp.vl * fnt().H(); } return(new Point(x, y)); }
private bool FindNextFromImpl(DPos s, ref DPos beg, ref DPos end) { Searcher.SearchWord = this.SearchWord; // 1行ずつサーチ //Document d = view.GetDocument(); //for( int mbg=0,med=0,e=d.tln(); s.tl<e; ++s.tl, s.ad=0 ) for (int mbg = 0, med = 0, e = document.tln(); s.tl < e; ++s.tl, s.ad = 0) { //if (Searcher.Search(d.tl(s.tl).ToString(), d.GetLength(s.tl), s.ad, ref mbg, ref med)) { if (Searcher.Search(document.GetText(s.tl), document.GetLength(s.tl), s.ad, ref mbg, ref med)) { beg.tl = end.tl = s.tl; beg.ad = mbg; end.ad = med; return(true); // 発見 } } return(false); }
public bool FindNextImpl() { // カーソル位置取得 //VPos stt, end; //view.cursor.getCurPos( out stt, out end ); DPos stt, end; view.GetSelction(out stt, out end); // 選択範囲ありなら、選択範囲先頭の1文字先から検索 // そうでなければカーソル位置から検索 DPos s = new DPos(stt.tl, stt.ad); if (stt != end) { //if (stt.ad == view.Document.len(stt.tl)) if (stt.ad == document.GetLength(stt.tl)) { s = new DPos(stt.tl + 1, 0); } else { s = new DPos(stt.tl, stt.ad + 1); } } // 検索 DPos b = new DPos(); DPos e = new DPos(); if (FindNextFromImpl(s, ref b, ref e)) { // 見つかったら選択 //view.cursor.MoveCur(b, false); //view.cursor.MoveCur(e, true); view.SetSelction(b, e); return(true); } // 見つからなかった場合 return(false); }
internal DPos leftOf(DPos dp, bool wide) { if (dp.ad == 0) { // 行の先頭だが、ファイルの先頭ではない場合 // 一つ前の行の行末へ if (dp.tl > 0) { return(new DPos(dp.tl - 1, len(dp.tl - 1))); } return(dp); } else if (!wide) { // 行の途中で、普通に1文字戻る場合 string l = tl(dp.tl).ToString(); //if (dp.ad >= 2 && Util.isLowSurrogate(l[dp.ad - 1]) && Util.isHighSurrogate(l[dp.ad - 2])) // return new DPos(dp.tl, dp.ad - 2); return(new DPos(dp.tl, dp.ad - 1)); } else { //TODO 行の途中で、1単語分戻る場合 //const uchar* f = pl(dp.tl); //ulong s = dp.ad - 1; //while ((f[s] >> 5) == 0 && 0 <= s) // --s; //return DPos(dp.tl, s); var f = text_[dp.tl].Text; var s = dp.ad - 1; Util.CharType ctype = Util.getCharType(f[s]); while (0 < s && Util.getCharType(f[s]) == ctype) { --s; } s = s != 0 ? ++s : s; return(new DPos(dp.tl, s)); } }
internal bool DeletingOperation(ref DPos s, ref DPos e, out string undobuf) { // 位置補正 CorrectPos(ref s); CorrectPos(ref e); CorrectPos(ref s, ref e); // 削除される量をカウント int undosiz = getRangeLength(s, e); // Undo操作用バッファ確保 //undobuf = new unicode[undosiz + 1]; //getText(undobuf, s, e); undobuf = GetText(s, e); // 削除る if (s.tl == e.tl) { // 一行内削除 //text_[s.tl].RemoveAt(s.ad, e.ad - s.ad); text_[s.tl].Text.Remove(s.ad, e.ad - s.ad); } else { // 先頭行の後ろを削除 //text_[s.tl].RemoveToTail(s.ad); text_[s.tl].Text.Remove(s.ad); // 終了行の残り部分をくっつける //text_[s.tl].InsertToTail(tl(e.tl) + e.ad, len(e.tl) - e.ad); string val = tl(e.tl).Substring(e.ad, len(e.tl) - e.ad).ToString(); text_[s.tl].Text.Append(val); // いらん行を削除 //text_.RemoveAt(s.tl + 1, e.tl - s.tl); text_.RemoveRange(s.tl + 1, e.tl - s.tl); } // 再解析 //return ReParse(s.tl, s.tl); return(ReParse(s.ad, s.tl, s.tl)); }
public bool FindPrevImpl() { // カーソル位置取得 //VPos stt = new VPos(); //VPos end = new VPos(); //view.cursor.getCurPos( out stt, out end ); DPos stt, end; view.GetSelction(out stt, out end); if (stt.ad != 0 || stt.tl != 0) { // 選択範囲先頭の1文字前から検索 DPos s; if (stt.ad == 0) { //s = new DPos( stt.tl-1, view.Document.len(stt.tl-1) ); s = new DPos(stt.tl - 1, view.Document.GetLength(stt.tl - 1)); } else { s = new DPos(stt.tl, stt.ad - 1); } // 検索 DPos b = new DPos(); DPos e = new DPos(); if (FindPrevFromImpl(s, ref b, ref e)) { // 見つかったら選択 //view.cursor.MoveCur( b, false ); //view.cursor.MoveCur( e, true ); view.SetSelction(b, e); return(true); } } // 見つからなかった場合 return(false); }
// public void on_text_update(DPos s, DPos e, DPos e2, bool bAft, bool mCur) { // まず、折り返し位置再計算 // 置換範囲の先頭行を調整 int r3 = 0, r2 = 1, r1 = ReWrapSingle(s); // 残りを調整 if (s.tl != e.tl) { r2 = DeleteMulti(s.tl + 1, e.tl); } if (s.tl != e2.tl) { r3 = InsertMulti(s.tl + 1, e2.tl); } // この変更で横幅が… // if( "長くなったなてはいない" AND "短くなっちゃった可能性あり" ) // 横幅再計算(); if (!(r1 == 2 || r3 == 1) && (r1 == 0 || r2 == 0)) { UpdateTextCx(); } // スクロールバー修正 ReDrawType t = TextUpdate_ScrollBar(s, e, e2); bool doResize = false; // 行数に変化があって、行番号表示域の幅を変えなきゃならん時 if (e.tl != e2.tl && cvs_.on_tln_change(doc_.tln())) { doResize = true; } else if (bAft && t != ReDrawType.ALL) { t = ReDrawType.AFTER; } // カーソル移動 cur_.on_text_update(s, e, e2, mCur); // 再描画 if (doResize) { DoResize(true); } else { if (e.tl != e2.tl) // 行番号領域再描画の必要があるとき { ReDraw(ReDrawType.LNAREA, null); } //TODO DrawEventHandler if (DrawEventHandler != null) { //ReDraw(ReDrawType.ALL, s); ReDraw(ReDrawType.AFTER, s); } else { ReDraw(t, s); } } }
public Insert(DPos s, string str) { stt_ = new DPos(s); buf_ = str; }
public Delete(DPos s, DPos e) { stt_ = new DPos(s); end_ = new DPos(e); }
private void CorrectPos(ref DPos pos) { // 正常範囲に収まるように修正 pos.tl = Math.Min(pos.tl, tln() - 1); pos.ad = Math.Min(pos.ad, len(pos.tl)); }
public Replace(DPos s, DPos e, string str) { stt_ = new DPos(s); end_ = new DPos(e); buf_ = str; }