📄 textedit.cc
字号:
textfile->write(block, size); uint s = size; text_viewer_pos start, end; textfile->convert_ofs2line(o, &start.line, &start.pofs); textfile->convert_ofs2line(o+s, &end.line, &end.pofs); te->select_set(&start, &end); te->goto_line(bpos.line); te->cursor_pput(bpos.pofs); return cpos;}void delete_text_block(ht_text_editor *te, text_viewer_pos apos, text_viewer_pos bpos, text_viewer_pos cpos, text_viewer_pos sel_start, text_viewer_pos sel_end, bool copy, void **block, uint *size){ ht_textfile *textfile = te->get_textfile(); FileOfs s, e; if (textfile->convert_line2ofs(sel_start.line, sel_start.pofs, &s) && textfile->convert_line2ofs(sel_end.line, sel_end.pofs, &e) && copy) { uint sz = e-s; void *bl = malloc(sz); textfile->seek(s); textfile->read(bl, sz); *block = bl; *size = sz; } int k=0; if (sel_start.line < sel_end.line) { k=textfile->getlinelength(sel_start.line)-sel_start.pofs; } else { k=sel_end.pofs-sel_start.pofs; } te->delete_chars(sel_start.line, sel_start.pofs, k); if (sel_start.line < sel_end.line) { te->delete_chars(sel_end.line, 0, sel_end.pofs); if (sel_start.line+1 < sel_end.line) { te->delete_lines(sel_start.line+1, sel_end.line-sel_start.line-1); } te->concat_lines(sel_start.line); } te->unindent(cpos.line, cpos.pofs, apos.pofs-cpos.pofs); te->goto_line(apos.line); te->cursor_pput(apos.pofs); te->select_clear(); te->goto_line(bpos.line); te->cursor_pput(bpos.pofs);}/* * CLASS ht_undo_data_insert_block */ht_undo_data_insert_block::ht_undo_data_insert_block(text_viewer_pos *Apos, text_viewer_pos *Bpos, void *Block, uint Size){ apos = *Apos; bpos = *Bpos; sel_start.line = sel_end.line = 0; sel_start.pofs = sel_end.pofs = 0; size = Size; block = malloc(size); memcpy(block, Block, size);}ht_undo_data_insert_block::~ht_undo_data_insert_block(){ free(block);}uint ht_undo_data_insert_block::getsize(){ return (sizeof *this)+size;}void ht_undo_data_insert_block::gettext(char *text, uint maxlen){ ht_snprintf(text, maxlen, "insert block ...");}ObjectID ht_undo_data_insert_block::getObjectID() const{ return ATOM_HT_UNDO_DATA_INSERT_BLOCK;}void ht_undo_data_insert_block::apply(ht_text_editor *te){ cpos = insert_text_block(te, apos, bpos, block, size); if (text_viewer_pos_compare(&sel_start, &sel_end) == 0) { te->get_selection(&sel_start, &sel_end); }}void ht_undo_data_insert_block::unapply(ht_text_editor *te, bool *goto_only){ if (*goto_only && (bpos.line != te->top_line + te->cursory || te->physical_cursorx()!=bpos.pofs)) { te->goto_line(apos.line); te->cursor_pput(apos.pofs); te->goto_line(bpos.line); te->cursor_pput(bpos.pofs); return; } *goto_only = false; delete_text_block(te, bpos, apos, cpos, sel_start, sel_end, false, NULL, NULL);}/* * CLASS ht_undo_data_delete_block */ht_undo_data_delete_block::ht_undo_data_delete_block(text_viewer_pos *Apos, text_viewer_pos *Bpos, text_viewer_pos *Sel_start, text_viewer_pos *Sel_end){ apos = *Apos; bpos = *Bpos; sel_start = *Sel_start; sel_end = *Sel_end; size = 0; block = NULL;}ht_undo_data_delete_block::~ht_undo_data_delete_block(){ free(block);}uint ht_undo_data_delete_block::getsize(){ return (sizeof *this)+size;}void ht_undo_data_delete_block::gettext(char *text, uint maxlen){ // FIXME ht_snprintf(text, maxlen, "delete block ...");}ObjectID ht_undo_data_delete_block::getObjectID() const{ return ATOM_HT_UNDO_DATA_DELETE_BLOCK;}void ht_undo_data_delete_block::apply(ht_text_editor *te){ free(block); delete_text_block(te, apos, bpos, apos, sel_start, sel_end, true, &block, &size);}void ht_undo_data_delete_block::unapply(ht_text_editor *te, bool *goto_only){ if (*goto_only && (bpos.line != te->top_line + te->cursory || te->physical_cursorx()!=bpos.pofs)) { te->goto_line(sel_end.line); te->cursor_pput(sel_end.pofs); te->goto_line(bpos.line); te->cursor_pput(bpos.pofs); return; } *goto_only = false; insert_text_block(te, bpos, sel_end, block, size);}/* * CLASS ht_text_editor_undo */ht_text_editor_undo::ht_text_editor_undo(uint max_undo_size) : Array(true){ size = 0; max_size = max_undo_size; clean_state = 0; goto_state = true; current_position = 0;}int ht_text_editor_undo::get_current_position(){ return current_position;}void ht_text_editor_undo::insert_undo(ht_text_editor *tv, ht_undo_data *undo){ if (undo) { if (current_position != (int)count()) { // remove all pending redo's uint test = count(); for (uint i = current_position; i < test; i++) { ht_undo_data *u = (ht_undo_data*)get(findByIdx(current_position)); size -= u->getsize(); del(findByIdx(current_position)); } assert(current_position == (int)count()); // clean_state eventually becomes unreachable if (clean_state > current_position) { clean_state = -1; } } undo->apply(tv); uint gsize = undo->getsize(); while (size + gsize > max_size) { if (clean_state > -1) clean_state--; if (isEmpty()) { size -= ((ht_undo_data*)get(findFirst()))->getsize(); del(findFirst()); if (current_position) current_position--; } else { delete undo; return; } } if (!isEmpty() && !is_clean()) { ht_undo_data *u = (ht_undo_data*)get(findLast()); uint zsize = u->getsize(); if (u->combine(undo)) { size -= zsize; size += u->getsize(); delete undo; return; } } current_position++; insert(undo); size+=gsize; } goto_state = true;}void ht_text_editor_undo::mark_clean(){ clean_state = current_position; goto_state = true;}bool ht_text_editor_undo::is_clean(){ return clean_state == current_position;}bool ht_text_editor_undo::is_clean(int i){ return clean_state == i;}void ht_text_editor_undo::redo(ht_text_editor *te){ goto_state = true; if (current_position < (int)count()) { ht_undo_data *u = (ht_undo_data*)get(findByIdx(current_position)); u->apply(te); current_position++; }}void ht_text_editor_undo::undo(ht_text_editor *te, bool place_cursor_first){ if (current_position) { ht_undo_data *u = (ht_undo_data*)get(findByIdx(current_position-1)); bool goto_state_test = place_cursor_first ? goto_state : false; u->unapply(te, &goto_state_test); if (!goto_state_test) { current_position--; } goto_state = !goto_state_test; }}/* * */int text_viewer_pos_compare(text_viewer_pos *a, text_viewer_pos *b){ if (a->line==b->line) { return a->pofs-b->pofs; } return a->line-b->line;}/* * CLASS ht_text_viewer */void ht_text_viewer::init(Bounds *b, bool own_t, ht_textfile *t, Container *l){ ht_view::init(b, VO_OWNBUFFER | VO_SELECTABLE | VO_RESIZE, "text viewer"); VIEW_DEBUG_NAME("ht_text_viewer"); growmode = MK_GM(GMH_FIT, GMV_FIT); own_textfile = false; textfile = NULL; set_textfile(t, own_t); own_lexer = false; lexer = NULL;// set_lexer(l, own_l); lexers = l; top_line = 0; xofs = 0; cursorx = 0; cursory = 0; select_clear(); selectcursor = false; EOL_string = NULL; EOF_string = NULL; show_EOL = false; show_EOF = false; highlight_wrap = true; last_search_request = NULL; config_changed();}void ht_text_viewer::done(){ delete last_search_request; if (own_textfile) delete textfile; if (own_lexer && lexer) { lexer->done(); delete lexer; } free(EOL_string); free(EOF_string); ht_view::done();}uint ht_text_viewer::char_vsize(char c, uint x){ if (c=='\t') return tab_size - x % tab_size; return 1;}void ht_text_viewer::clipboard_copy_cmd(){ if (text_viewer_pos_compare(&sel_start, &sel_end)<0) { FileOfs s, e; if (textfile->convert_line2ofs(sel_start.line, sel_start.pofs, &s) && textfile->convert_line2ofs(sel_end.line, sel_end.pofs, &e)) { char dsc[1024]; String fn; ht_snprintf(dsc, sizeof dsc, "%y::%s", &textfile->getDesc(fn), desc); clipboard_copy(dsc, textfile, s, e-s); } }}void ht_text_viewer::config_changed(){ free(EOL_string); free(EOF_string); EOL_string = get_config_string("editor/EOL"); EOF_string = get_config_string("editor/EOF"); tab_size = get_config_dword("editor/tab size"); tab_size = MIN(MAX(tab_size, 1), 16); if (lexer) lexer->config_changed(); ht_view::config_changed();}bool ht_text_viewer::continue_search(){ if (last_search_request) { ht_search_result *r = NULL; FileOfs o, no; text_viewer_pos cursor; get_cursor_pos(&cursor); o = 0; pos_to_offset(&cursor, &o); no = o+1; try { if (last_search_request->search_class == SC_PHYSICAL) { text_search_pos start, end; start.offset = no; end.offset = last_search_end_ofs; r = search(last_search_request, &start, &end); } } catch (const Exception &e) { errorbox("error: %y", &e); } if (r) return show_search_result(r); } return false;}uint ht_text_viewer::cursor_up(uint n){ if (cursory>n) cursory-=n; else { n=scroll_up(n-cursory); cursory=0; } return n;}uint ht_text_viewer::cursor_down(uint n){ uint lmh=textfile->linecount()-top_line; if (lmh>(uint)size.h) lmh=size.h; if (cursory+n>lmh-1) { uint k = scroll_down(cursory+n-(lmh-1)); lmh = textfile->linecount()-top_line; if (lmh>(uint)size.h) lmh = size.h; n = k+(lmh-1)-cursory; cursory = lmh-1; } else cursory+=n; return n;}uint ht_text_viewer::cursor_left(uint n){ uint p; if (cursorx+xofs>n) p=cursorx+xofs-n; else p=0; cursor_vput(p); return 1;}uint ht_text_viewer::cursor_right(uint n){ cursor_vput(cursorx+xofs+n); return 1;}void ht_text_viewer::cursor_home(){ cursor_vput(0);}void ht_text_viewer::cursor_end(){ cursor_vput(get_line_vlength(top_line+cursory));}void ht_text_viewer::cursor_pput(uint dx){ uint vx = 0, px = 0; char line[1024]; char *linep=line; uint linelen; if (!textfile->getline(top_line+cursory, 0, line, sizeof line, &linelen, NULL)) return; while (linelen--) { if (px==dx) break; int k = char_vsize(*(linep++), vx); vx += k; px++; } vx += dx-px; if (xofs > vx) { cursorx = 0; xofs = vx; } else { cursorx = vx-xofs; if (cursorx > (uint)size.w-1) { xofs += cursorx-(size.w-1); cursorx = size.w-1; } }}void ht_text_viewer::cursor_set(text_viewer_pos *pos){ goto_line(pos->line); cursor_pput(pos->pofs);}void ht_text_viewer::cursor_vput(uint vx){ if ((vx>=xofs) && (vx<xofs+size.w)) { cursorx=vx-xofs; } else if (vx<xofs) { xofs=vx; cursorx=0; } else if (vx>(uint)size.w-1) { xofs=vx-(size.w-1); cursorx=size.w-1; } else { xofs=0; cursorx=vx; }}void ht_text_viewer::draw(){//#define TIME_DRAW#ifdef TIME_DRAW timer_handle h=new_timer(); start_timer(h);#endif /* TIME_DRAW */ if (!textfile) return; vcp bgcolor = get_bgcolor(); vcp metacolor = lexer ? lexer->getcolor_syntax(palidx_syntax_meta) : VCP(VCP_BACKGROUND(bgcolor), VCP_BACKGROUND(bgcolor)); bool drawmeta = (lexer != NULL); clear(bgcolor); char line[1024]; text_viewer_pos pos; pos.line = top_line; int y; for (y=0; y < size.h; y++) { lexer_state state; pos.pofs = 0;//FIXME:debug: if (!textfile->getline((top_line+y)|0x80000000, line, sizeof line, &state)) break; uint linelen; if (!textfile->getline(top_line+y, 0, line, sizeof line, &linelen, &state)) break; line[linelen] = 0; uint x=0; if (lexer) { char *linep=(char*)line; uint toklen; lexer_token tok; bool start_of_line=true; text_pos p; p.line=pos.line; p.pofs=pos.pofs; int prev_linelen = -1; while ((tok = lexer->gettoken(linep, linelen, p, start_of_line, &state, &toklen)) || (!*linep && (linelen>0))) { uint k, i; uint vtoklen=toklen; bool print=true; bool is_tab=((toklen==1) && (*linep=='\t')); vcp color=lexer->gettoken_color(tok); if (is_tab) vtoklen=tab_size-x%tab_size; if (x >= xofs) { k = x-xofs; i = 0; if (k > (uint)size.w-1) { break; } } else if (x+vtoklen >= xofs) { k=0; i=xofs-x; } else { print=false; } if (print) { if (is_tab) { char tab[17]; uint z; for (z=0; z<vtoklen; z++) tab[z]=' '; tab[z]=0; render_str(k, y, color, &pos, vtoklen-i, tab+i, false); } else { render_str(k, y, color, &pos, vtoklen-i, linep+i, true); } } x += vtoklen; linep += toklen; linelen -= toklen; pos.pofs += toklen; start_of_line = false; p.line = pos.line; p.pofs = pos.pofs; if (!linelen && !prev_linelen) break; prev_linelen = linelen; } if (drawmeta) render_meta(x-xofs, y, &pos, metacolor); } else { char *linep=line; while (linelen--) { uint vtoklen=char_vsize(*linep, x); if (x>=xofs) { if (x-xofs>(uint)size.w-1) break; if (*linep=='\t') { vcp c=bgcolor; char tab[17]; uint z; for (z=0; z<vtoklen; z++) tab[z]=' '; tab[z]=0; render_str_color(&c, &pos); buf->nprint(x-xofs, y, c, tab, z); } else { vcp c=bgcolor; render_str_color(&c, &pos); buf->printChar(x-xofs, y, c, *linep); } } x+=vtoklen; linep++; pos.pofs++; } if (drawmeta) render_meta(x-xofs, y, &pos, metacolor); } if (highlight_wrap && pos.line < sel_end.line && pos.line >= sel_start.line) { int q = (drawmeta && show_EOL) ? strlen(EOL_string) : 0; int p = (x+q>xofs) ? x+q-xofs : 0; fill(p, y, size.w-p, 1, getcolor(palidx_generic_input_selected), ' '); } pos.line++; } if (focused) setcursor(cursorx, cursory, get_cursor_mode());#ifdef TIME_DRAW stop_timer(h); int tix=get_timer_tick(h); delete_timer(h); buf_printf(40, 0, bgcolor, "%dtix", tix);#endif /* TIME_DRAW */}const char *ht_text_viewer::func(uint i, bool execute){ switch (i) { case 5: { if (execute) { sendmsg(cmd_text_viewer_goto); } return "goto"; } case 7: { if (execute) { text_viewer_pos end_pos; uint search_caps = SEARCHMODE_BIN; ht_search_request *request = text_search_dialog(this, search_caps, &end_pos); ht_search_result *result = NULL; if (request) { text_search_pos start, end; text_viewer_pos cursor; get_cursor_pos(&cursor); pos_to_offset(&cursor, &start.offset); end.offset = 0xffffffff; result = search(request, &start, &end); if (result) { // FIXME: !!!!!!!!? if (!show_search_result(result)) infobox("couldn't display result (internal error)"); delete result; } else infobox("not found"); } } return "search"; } default: return false; } return 0;}vcp ht_text_viewer::get_bgcolor(){ return getcolor(palidx_generic_body);}void ht_text_viewer::get_cursor_pos(text_viewer_pos *cursor){ cursor->pofs = physical_cursorx(); cursor->line = top_line+cursory;}CursorMode ht_text_viewer::get_cursor_mode()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -