📄 textedit.cc
字号:
delete lexer; } // FIXME: is this "the right thing"? if (l) l->config_changed(); lexer = l; own_lexer = own_l; textfile->set_lexer(l);}void ht_text_viewer::set_textfile(ht_textfile *t, bool own_t){ if (own_textfile) delete textfile; textfile = t; own_textfile = own_t;}bool ht_text_viewer::show_search_result(ht_search_result *result){ switch (result->search_class) { case SC_PHYSICAL: { ht_physical_search_result *r = (ht_physical_search_result*)result; text_viewer_pos start, end; textfile->convert_ofs2line(r->offset, &start.line, &start.pofs); textfile->convert_ofs2line(r->offset+r->size, &end.line, &end.pofs); select_set(&start, &end); cursor_set(&start); } } return true;}/* * CLASS ht_text_editor */void ht_text_editor::init(Bounds *b, bool own_t, ht_textfile *t, Container *l, uint e){ ht_text_viewer::init(b, own_t, t, l); edit_options = e; if (edit_options & TEXTEDITOPT_UNDO) { undo_list = new ht_text_editor_undo(1024*1024); } else { undo_list = NULL; } overwrite_mode = false; show_EOL = true; show_EOF = true;}void ht_text_editor::done(){ delete undo_list; ht_text_viewer::done();}void ht_text_editor::clipboard_cut_cmd(){ clipboard_copy_cmd(); clipboard_delete_cmd();}void ht_text_editor::clipboard_delete_cmd(){ if (sel_start.line || sel_start.pofs || sel_end.line || sel_end.pofs) { text_viewer_pos apos, bpos; uint px = physical_cursorx(); apos.line = top_line+cursory; apos.pofs = px; bpos = sel_start; textoperation_apply(new ht_undo_data_delete_block(&apos, &bpos, &sel_start, &sel_end)); }}void ht_text_editor::clipboard_paste_cmd(){ uint bsize = clipboard_getsize(); void *block = malloc(bsize); clipboard_paste(block, bsize); text_viewer_pos apos, bpos; uint px = physical_cursorx(); apos.line = bpos.line = top_line+cursory; apos.pofs = bpos.pofs = px; textoperation_apply(new ht_undo_data_insert_block(&apos, &bpos, block, bsize)); free(block);}bool ht_text_editor::concat_lines(uint a){ uint b = a+1; if (textfile->has_line(a) && textfile->has_line(b)) { uint alen = textfile->getlinelength(a); char *aline = ht_malloc(alen+1); uint alinelen; textfile->getline(a, 0, aline, alen+1, &alinelen, NULL); text_viewer_pos ss, se; ss=sel_start; se=sel_end; insert_chars(b, 0, aline, alinelen); free(aline); delete_lines(a, 1); if (b > ss.line) { if (b == se.line) { se.pofs += alen; se.line--; } else if (b < se.line) { se.line--; } } else { if (b == ss.line) { ss.pofs += alen; } ss.line--; se.line--; } sel_start = ss; sel_end = se; normalize_selection(); return true; } return false;}void ht_text_editor::config_changed(){ auto_indent = get_config_dword("editor/auto indent"); ht_text_viewer::config_changed();}void ht_text_editor::delete_chars(uint line, uint ofs, uint count){ text_viewer_pos pos; pos.line=line; pos.pofs=ofs; if ((sel_end.line==pos.line) && (text_viewer_pos_compare(&pos, &sel_start)>=0) && (text_viewer_pos_compare(&pos, &sel_end)<0)) { sel_end.pofs-=count; } else if ((sel_start.line==pos.line) && (text_viewer_pos_compare(&pos, &sel_start)<0)) { sel_start.pofs-=count; if (sel_end.line==pos.line) sel_end.pofs-=count; } textfile->delete_chars(line, ofs, count);}void ht_text_editor::delete_lines(uint line, uint count){ if (sel_start.line+1>line) sel_start.line--; if (sel_end.line>line) sel_end.line--; normalize_selection(); textfile->delete_lines(line, count);}const char *ht_text_editor::func(uint i, bool execute){ switch (i) { case 2: if (execute) { String fn; if (!textfile->getFilename(fn).isEmpty()) { sendmsg(cmd_file_save); } else { app->sendmsg(cmd_file_saveas); bool dirty = true; FileOfs start = 0; FileOfs end = 0x7fffffff; textfile->cntl(FCNTL_MODS_IS_DIRTY, start, end, &dirty); if (undo_list && !dirty) { undo_list->mark_clean(); } } } return "save"; } return ht_text_viewer::func(i, execute);}vcp ht_text_editor::get_bgcolor(){ return getcolor(focused ? palidx_generic_input_focused : palidx_generic_input_unfocused);}CursorMode ht_text_editor::get_cursor_mode(){ return overwrite_mode ? CURSOR_BOLD : CURSOR_NORMAL;}int ht_text_editor::get_pindicator_str(char *buf, int max_len){ ht_syntax_lexer *l = get_lexer(); const char *ln = l ? l->getname() : NULL; bool dirty = true; textfile->cntl(FCNTL_MODS_IS_DIRTY, 0ULL, 0x7fffffffULL, &dirty); if (ln) { return ht_snprintf(buf, max_len, " %c%d:%d (%s) ", dirty ? '*' : ' ', top_line+cursory+1, xofs+cursorx+1, ln); } else { return ht_snprintf(buf, max_len, " %c%d:%d ", dirty ? '*' : ' ', top_line+cursory+1, xofs+cursorx+1); }}void ht_text_editor::handlemsg(htmsg *msg){ switch (msg->msg) { case msg_keypressed: { int k=msg->data1.integer; switch (k) { case K_Insert: { overwrite_mode = !overwrite_mode; dirtyview(); clearmsg(msg); return; } case K_Return: { uint px=physical_cursorx(); text_viewer_pos apos, bpos; apos.line = top_line+cursory; bpos.line = apos.line+1; apos.pofs = px; bpos.pofs = 0; if (auto_indent) { int i=0; bpos.pofs = 0xffffffff; while (bpos.pofs==0xffffffff && (apos.line-i) && (i<32)) { bpos.pofs = get_line_indent(apos.line-i); i++; } if (bpos.pofs == 0xffffffff) bpos.pofs = 0; } uint indent = bpos.pofs; if (px >= get_line_length(top_line+cursory)) indent = 0; textoperation_apply(new ht_undo_data_split_line(&apos, &bpos, indent)); dirtyview(); clearmsg(msg); return; } case K_Delete: { uint cx=physical_cursorx(); if (cx < get_line_length(top_line+cursory)) { uint px=physical_cursorx(); text_viewer_pos apos, bpos; char s[1024]; apos.line = bpos.line = top_line+cursory; apos.pofs = px; bpos.pofs = px; uint i; textfile->getline(apos.line, 0, s, 1024, &i, NULL); textoperation_apply(new ht_undo_data_delete_string2(&apos, &bpos, &s[px], 1)); } else if (textfile->has_line(top_line+cursory+1)) { uint px=physical_cursorx(); text_viewer_pos apos, bpos; apos.line = top_line+cursory; apos.pofs = px; bpos.line = top_line+cursory; bpos.pofs = px; textoperation_apply(new ht_undo_data_join_line(&apos, &bpos)); } dirtyview(); clearmsg(msg); return; } case K_Backspace: { uint cx=physical_cursorx(); if (cx) { if (cx <= textfile->getlinelength(top_line+cursory)) { uint px=physical_cursorx()-1; text_viewer_pos apos, bpos; char s[1024]; apos.line = bpos.line = top_line+cursory; apos.pofs = cx; bpos.pofs = px; uint i; textfile->getline(apos.line, 0, s, 1024, &i, NULL); textoperation_apply(new ht_undo_data_delete_string(&apos, &bpos, &s[px], 1)); } else { // place cursor only cursor_pput(cx-1); } } else { if (top_line+cursory) { uint px=physical_cursorx(); text_viewer_pos apos, bpos; apos.line = top_line+cursory; apos.pofs = px; bpos.line = apos.line-1; bpos.pofs = get_line_length(bpos.line); textoperation_apply(new ht_undo_data_join_line(&apos, &bpos)); } } dirtyview(); clearmsg(msg); return; } case K_Meta_U: case K_Meta_Backspace: { sendmsg(cmd_text_editor_undo); clearmsg(msg); return; } case K_Meta_R: { sendmsg(cmd_text_editor_redo); clearmsg(msg); return; } case K_Meta_V: case K_Shift_Insert: sendmsg(cmd_edit_paste); clearmsg(msg); return; case K_Meta_X: case K_Shift_Delete: sendmsg(cmd_edit_cut); clearmsg(msg); return; case K_Meta_D: case K_Control_Delete: sendmsg(cmd_edit_delete); clearmsg(msg); return; case K_Control_Y: sendmsg(cmd_text_editor_delete_line); clearmsg(msg); return; default: { int k=msg->data1.integer; if (((k>=' ') && (k<=255)) || ((k=='\t') && (edit_options & TEXTEDITOPT_INPUTTABS))) { char s=k; text_viewer_pos apos, bpos; uint px=physical_cursorx(); apos.line = bpos.line = top_line+cursory; apos.pofs = px; bpos.pofs = px+1; if (overwrite_mode) { char old[1024]; uint i, j=0; textfile->getline(apos.line, 0, old, 1024, &i, NULL); if (i>px) j = 1; textoperation_apply(new ht_undo_data_overwrite_string(&apos, &bpos, &s, 1, &old[px], j)); } else { textoperation_apply(new ht_undo_data_insert_string(&apos, &bpos, &s, 1)); } dirtyview(); clearmsg(msg); return; } } } break; } case msg_contextmenuquery: { ht_static_context_menu *m=new ht_static_context_menu(); m->init("~Texteditor"); if (undo_list) { char buf[30], buf2[20]; // FIXME: implementme correctly/better/* if (undo_list->current_position) { ((ht_undo_data*)undo_list->get(undo_list->current_position-1))->gettext(buf2, sizeof buf2); } else { }*/ buf2[0] = 0; ht_snprintf(buf, sizeof buf, "~Undo %s", buf2); m->insert_entry(buf, "Alt+U", cmd_text_editor_undo, 0, 1); m->insert_entry("~Redo", "Alt+R", cmd_text_editor_redo, 0, 1); m->insert_entry("~Protocol", "Alt+P", cmd_text_editor_protocol, K_Meta_P, 1); m->insert_separator(); } m->insert_entry("Change ~highlight", "", cmd_text_viewer_change_highlight, 0, 1); m->insert_separator(); // FIXME: somewhat hacked m->insert_entry("~Delete line", "Control+Y", cmd_text_editor_delete_line, 0, 1); m->insert_separator(); m->insert_entry("~Go to line", "", cmd_text_viewer_goto, 0, 1); msg->msg = msg_retval; msg->data1.ptr = m; return; } case cmd_edit_paste: { clipboard_paste_cmd(); dirtyview(); clearmsg(msg); return; } case cmd_edit_cut: { clipboard_cut_cmd(); dirtyview(); clearmsg(msg); return; } case cmd_edit_delete: { clipboard_delete_cmd(); dirtyview(); clearmsg(msg); return; } case cmd_file_save: { if (save()) clearmsg(msg); return; } case cmd_text_editor_undo: { undo(true); dirtyview(); clearmsg(msg); return; } case cmd_text_editor_redo: { redo(); dirtyview(); clearmsg(msg); return; } case cmd_text_editor_protocol: { show_protocol(); dirtyview(); clearmsg(msg); return; } case cmd_text_editor_delete_line: { if (top_line+cursory <= textfile->linecount()-1) { text_viewer_pos apos, bpos, a, b; apos.line = top_line+cursory; apos.pofs = physical_cursorx(); bpos.line = top_line+cursory; bpos.pofs = 0; a.line = top_line+cursory; a.pofs = 0; b = a; // if last line if (b.line+1 > textfile->linecount()-1) { b.pofs = textfile->getlinelength(b.line); } else { b.line++; } if ((a.line != b.line) || (a.pofs != b.pofs)) textoperation_apply(new ht_undo_data_delete_block(&apos, &bpos, &a, &b)); } dirtyview(); clearmsg(msg); return; } } ht_text_viewer::handlemsg(msg);}void ht_text_editor::indent(uint line, uint start, uint size){ char *w = ht_malloc(size); memset(w, ' ', size); textfile->insert_chars(line, start, w, size); free(w);}void ht_text_editor::unindent(uint line, uint start, uint size){ textfile->delete_chars(line, start, size);}void ht_text_editor::insert_chars(uint line, uint ofs, void *chars, uint len){ text_viewer_pos pos; pos.line=line; pos.pofs=ofs; if ((sel_end.line==pos.line) && (text_viewer_pos_compare(&pos, &sel_start)>=0) && (text_viewer_pos_compare(&pos, &sel_end)<0)) { sel_end.pofs+=len; } else if ((sel_start.line==pos.line) && (text_viewer_pos_compare(&pos, &sel_start)<0)) { sel_start.pofs+=len; if (sel_end.line==pos.line) sel_end.pofs+=len; } textfile->insert_chars(line, ofs, chars, len);}void ht_text_editor::insert_lines(uint line, uint count){ if (sel_start.line+1>line) sel_start.line++; if (sel_end.line>line) sel_end.line++; normalize_selection(); textfile->insert_lines(line, count);}bool ht_text_editor::save(){// asm(".byte 0xcc"); String oldname; if (textfile->getFilename(oldname).isEmpty()) return false; dirtyview(); TempFile temp(IOAM_READ | IOAM_WRITE); ht_ltextfile *old = dynamic_cast<ht_ltextfile *>(textfile->getLayered()); String blub; old->getDesc(blub); old->seek(0); old->copyAllTo(&temp); pstat_t st1, st2; old->pstat(st1); temp.pstat(st2); if (st1.size != st2.size) { errorbox("couldn't write backup file - file not saved. (o=%qd, t=%qd)", st1.size, st2.size); return false; } old->setAccessMode(IOAM_WRITE); File *f = old->getLayered(); f->truncate(0); temp.seek(0); temp.copyAllTo(f); old->setAccessMode(IOAM_READ); old->reread();// textfile->set_layered_assume(old, true, true); if (undo_list) { undo_list->mark_clean(); } return true;}void ht_text_editor::show_protocol(){ Bounds c, b; app->getbounds(&c); b.w=c.w*5/6; uint bh=b.h=c.h*5/6; b.x=(c.w-b.w)/2; b.y=(c.h-b.h)/2; ht_dialog *dialog; NEW_OBJECT(dialog, ht_dialog, &b, "protocol", FS_KILLER | FS_TITLE | FS_MOVE); b.assign(1, 0, b.w-4, 1); ht_statictext *text; NEW_OBJECT(text, ht_statictext, &b, " ", align_left); dialog->insert(text); b.y = 1; b.h = bh-5; ht_text_listbox *list; NEW_OBJECT(list, ht_text_listbox, &b, 2, 1); uint cp = undo_list->get_current_position(); const char *od; if (undo_list->is_clean(0)) { od = "disk"; } else { od = " "; } list->insert_str(0, od, "--- initial state ---"); for (uint i=0; i<undo_list->count(); i++) { char buf[1024]; ((ht_undo_data*)(*undo_list)[i])->gettext(buf, 1024); if (undo_list->is_clean(i+1)) { od = "disk"; } else { od = " "; } list->insert_str(i+1, od, buf); } list->update(); list->gotoItemByPosition(cp); dialog->insert(list); if (dialog->run(false) == button_ok) { ht_listbox_data d; ViewDataBuf vdb(list, &d, sizeof d); int a = list->getID(d.data->cursor_ptr); int b = cp; if (a-b < 0) { for (int i=0; i < b-a; i++) { undo(false); } } else if (a-b > 0) { for (int i=0; i < a-b; i++) { redo(); } } } dialog->done(); delete dialog;}void ht_text_editor::split_line(uint a, uint pos){ uint l=textfile->getlinelength(a); if (pos>l) pos=l; char *aline = ht_malloc(pos+1); uint alinelen; textfile->getline(a, 0, aline, pos+1, &alinelen, NULL); text_viewer_pos p, ss, se; p.line=a; p.pofs=pos; ss=sel_start; se=sel_end; insert_lines(a, 1); insert_chars(a, 0, aline, alinelen); delete_chars(a+1, 0, pos); free(aline); if (text_viewer_pos_compare(&p, &ss)>0) { if (text_viewer_pos_compare(&p, &se)<0) { if (se.line==p.line) { se.pofs-=pos; } se.line++; } } else { if (ss.line==p.line) { ss.pofs-=pos; } ss.line++; se.line++; } sel_start=ss; sel_end=se; normalize_selection();}void ht_text_editor::textoperation_apply(ht_undo_data *ud){ if (undo_list) { undo_list->insert_undo(this, ud); } else { ud->apply(this); delete ud; }}void ht_text_editor::redo(){ if (undo_list) { undo_list->redo(this); if (undo_list->is_clean()) textfile->cntl(FCNTL_MODS_CLEAR_DIRTY_RANGE, 0ULL, 0ULL); }}void ht_text_editor::undo(bool place_cursor_first){ if (undo_list) { undo_list->undo(this, place_cursor_first); if (undo_list->is_clean()) textfile->cntl(FCNTL_MODS_CLEAR_DIRTY_RANGE, 0ULL, 0ULL); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -