edit.c 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867
  1. /* editor low level data handling and cursor fundamentals.
  2. Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
  3. 2007 Free Software Foundation, Inc.
  4. Authors: 1996, 1997 Paul Sheer
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. 02110-1301, USA.
  17. */
  18. #include <config.h>
  19. #include <stdio.h>
  20. #include <stdarg.h>
  21. #include <sys/types.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include <errno.h>
  26. #include <sys/stat.h>
  27. #include <stdlib.h>
  28. #include "../src/global.h"
  29. #include "edit.h"
  30. #include "editlock.h"
  31. #include "edit-widget.h"
  32. #include "editcmddef.h"
  33. #include "usermap.h"
  34. #include "../src/cmd.h" /* view_other_cmd() */
  35. #include "../src/user.h" /* user_menu_cmd() */
  36. #include "../src/wtools.h" /* query_dialog() */
  37. #include "../src/timefmt.h" /* time formatting */
  38. /*
  39. what editor are we going to emulate? one of EDIT_KEY_EMULATION_NORMAL
  40. or EDIT_KEY_EMULATION_EMACS
  41. */
  42. int edit_key_emulation = EDIT_KEY_EMULATION_NORMAL;
  43. int option_word_wrap_line_length = 72;
  44. int option_typewriter_wrap = 0;
  45. int option_auto_para_formatting = 0;
  46. int option_tab_spacing = 8;
  47. int option_fill_tabs_with_spaces = 0;
  48. int option_return_does_auto_indent = 1;
  49. int option_backspace_through_tabs = 0;
  50. int option_fake_half_tabs = 1;
  51. int option_save_mode = EDIT_QUICK_SAVE;
  52. int option_save_position = 1;
  53. int option_max_undo = 32768;
  54. int option_edit_right_extreme = 0;
  55. int option_edit_left_extreme = 0;
  56. int option_edit_top_extreme = 0;
  57. int option_edit_bottom_extreme = 0;
  58. const char *option_whole_chars_search = "0123456789abcdefghijklmnopqrstuvwxyz_";
  59. char *option_backup_ext = NULL;
  60. /*-
  61. *
  62. * here's a quick sketch of the layout: (don't run this through indent.)
  63. *
  64. * (b1 is buffers1 and b2 is buffers2)
  65. *
  66. * |
  67. * \0\0\0\0\0m e _ f i l e . \nf i n . \n|T h i s _ i s _ s o\0\0\0\0\0\0\0\0\0
  68. * ______________________________________|______________________________________
  69. * |
  70. * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
  71. * |-> |-> |-> |-> |-> |-> |
  72. * |
  73. * _<------------------------->|<----------------->_
  74. * WEdit->curs2 | WEdit->curs1
  75. * ^ | ^
  76. * | ^|^ |
  77. * cursor ||| cursor
  78. * |||
  79. * file end|||file beginning
  80. * |
  81. * |
  82. *
  83. * _
  84. * This_is_some_file
  85. * fin.
  86. */
  87. static void user_menu (WEdit *edit);
  88. #ifndef UTF8
  89. int edit_get_byte (WEdit * edit, long byte_index)
  90. #else
  91. mc_wchar_t edit_get_byte (WEdit * edit, long byte_index)
  92. #endif
  93. {
  94. unsigned long p;
  95. if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
  96. return '\n';
  97. if (byte_index >= edit->curs1) {
  98. p = edit->curs1 + edit->curs2 - byte_index - 1;
  99. return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
  100. } else {
  101. return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
  102. }
  103. }
  104. /*
  105. * Initialize the buffers for an empty files.
  106. */
  107. static void
  108. edit_init_buffers (WEdit *edit)
  109. {
  110. int j;
  111. for (j = 0; j <= MAXBUFF; j++) {
  112. edit->buffers1[j] = NULL;
  113. edit->buffers2[j] = NULL;
  114. }
  115. edit->curs1 = 0;
  116. edit->curs2 = 0;
  117. edit->buffers2[0] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  118. }
  119. /*
  120. * Load file OR text into buffers. Set cursor to the beginning of file.
  121. * Return 1 on error.
  122. */
  123. static int
  124. edit_load_file_fast (WEdit *edit, const char *filename)
  125. {
  126. long buf, buf2;
  127. int file = -1;
  128. edit->curs2 = edit->last_byte;
  129. buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;
  130. if ((file = mc_open (filename, O_RDONLY | O_BINARY)) == -1) {
  131. GString *errmsg = g_string_new(NULL);
  132. g_string_sprintf(errmsg, _(" Cannot open %s for reading "), filename);
  133. edit_error_dialog (_("Error"), get_sys_error (errmsg->str));
  134. g_string_free (errmsg, TRUE);
  135. return 1;
  136. }
  137. if (!edit->buffers2[buf2])
  138. edit->buffers2[buf2] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  139. mc_read (file,
  140. (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE -
  141. (edit->curs2 & M_EDIT_BUF_SIZE),
  142. edit->curs2 & M_EDIT_BUF_SIZE);
  143. for (buf = buf2 - 1; buf >= 0; buf--) {
  144. /* edit->buffers2[0] is already allocated */
  145. if (!edit->buffers2[buf])
  146. edit->buffers2[buf] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  147. mc_read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
  148. }
  149. mc_close (file);
  150. return 0;
  151. }
  152. /* detecting an error on save is easy: just check if every byte has been written. */
  153. /* detecting an error on read, is not so easy 'cos there is not way to tell
  154. whether you read everything or not. */
  155. /* FIXME: add proper `triple_pipe_open' to read, write and check errors. */
  156. static const struct edit_filters {
  157. const char *read, *write, *extension;
  158. } all_filters[] = {
  159. { "bzip2 -cd %s 2>&1", "bzip2 > %s", ".bz2" },
  160. { "gzip -cd %s 2>&1", "gzip > %s", ".gz" },
  161. { "gzip -cd %s 2>&1", "gzip > %s", ".Z" }
  162. };
  163. /* Return index of the filter or -1 is there is no appropriate filter */
  164. static int edit_find_filter (const char *filename)
  165. {
  166. size_t i, l, e;
  167. if (!filename)
  168. return -1;
  169. l = strlen (filename);
  170. for (i = 0; i < sizeof (all_filters) / sizeof (all_filters[0]); i++) {
  171. e = strlen (all_filters[i].extension);
  172. if (l > e)
  173. if (!strcmp (all_filters[i].extension, filename + l - e))
  174. return i;
  175. }
  176. return -1;
  177. }
  178. static char *
  179. edit_get_filter (const char *filename)
  180. {
  181. int i, l;
  182. char *p, *quoted_name;
  183. i = edit_find_filter (filename);
  184. if (i < 0)
  185. return 0;
  186. quoted_name = name_quote (filename, 0);
  187. l = strlen (quoted_name);
  188. p = g_malloc (strlen (all_filters[i].read) + l + 2);
  189. sprintf (p, all_filters[i].read, quoted_name);
  190. g_free (quoted_name);
  191. return p;
  192. }
  193. char *
  194. edit_get_write_filter (const char *write_name, const char *filename)
  195. {
  196. int i, l;
  197. char *p, *writename;
  198. i = edit_find_filter (filename);
  199. if (i < 0)
  200. return 0;
  201. writename = name_quote (write_name, 0);
  202. l = strlen (writename);
  203. p = g_malloc (strlen (all_filters[i].write) + l + 2);
  204. sprintf (p, all_filters[i].write, writename);
  205. g_free (writename);
  206. return p;
  207. }
  208. static long
  209. edit_insert_stream (WEdit * edit, FILE * f)
  210. {
  211. int c;
  212. long i = 0;
  213. #ifndef UTF8
  214. while ((c = fgetc (f)) != EOF) {
  215. edit_insert (edit, c);
  216. i++;
  217. #else /* UTF8 */
  218. unsigned char buf[MB_LEN_MAX];
  219. int charpos = 0;
  220. mbstate_t mbs;
  221. while ((c = fgetc (f)) != EOF) {
  222. mc_wchar_t wc;
  223. int size;
  224. int j;
  225. buf[charpos++] = c;
  226. memset (&mbs, 0, sizeof (mbs));
  227. size = mbrtowc(&wc, (char *)buf, charpos, &mbs);
  228. if (size == -2)
  229. continue; /* incomplete */
  230. else if (size >= 0) {
  231. edit_insert (edit, wc);
  232. i++;
  233. charpos = 0;
  234. continue;
  235. }
  236. else {
  237. /* invalid */
  238. #ifdef __STDC_ISO_10646__
  239. for (j=0; j<charpos; j++)
  240. edit_insert (edit, BINARY_CHAR_OFFSET + (mc_wchar_t)buf[j]);
  241. #endif
  242. charpos = 0;
  243. }
  244. #endif /* UTF8 */
  245. }
  246. return i;
  247. }
  248. long edit_write_stream (WEdit * edit, FILE * f)
  249. {
  250. long i;
  251. #ifndef UTF8
  252. for (i = 0; i < edit->last_byte; i++)
  253. if (fputc (edit_get_byte (edit, i), f) < 0)
  254. break;
  255. #else /* UTF8 */
  256. for (i = 0; i < edit->last_byte; i++) {
  257. mc_wchar_t wc = edit_get_byte (edit, i);
  258. int res;
  259. char tmpbuf[MB_LEN_MAX];
  260. mbstate_t mbs;
  261. memset (&mbs, 0, sizeof (mbs));
  262. #ifdef __STDC_ISO_10646__
  263. if (wc >= BINARY_CHAR_OFFSET && wc < (BINARY_CHAR_OFFSET + 256)) {
  264. res = 1;
  265. tmpbuf[0] = (char) (wc - BINARY_CHAR_OFFSET);
  266. } else
  267. #endif
  268. res = wcrtomb(tmpbuf, wc, &mbs);
  269. if (res > 0) {
  270. if (fwrite(tmpbuf, res, 1, f) != 1)
  271. break;
  272. }
  273. }
  274. #endif /* UTF8 */
  275. return i;
  276. }
  277. #define TEMP_BUF_LEN 1024
  278. /* inserts a file at the cursor, returns 1 on success */
  279. int
  280. edit_insert_file (WEdit *edit, const char *filename)
  281. {
  282. char *p;
  283. if ((p = edit_get_filter (filename))) {
  284. FILE *f;
  285. long current = edit->curs1;
  286. f = (FILE *) popen (p, "r");
  287. if (f) {
  288. edit_insert_stream (edit, f);
  289. edit_cursor_move (edit, current - edit->curs1);
  290. if (pclose (f) > 0) {
  291. GString *errmsg = g_string_new (NULL);
  292. g_string_sprintf (errmsg, _(" Error reading from pipe: %s "), p);
  293. edit_error_dialog (_("Error"), errmsg->str);
  294. g_string_free (errmsg, TRUE);
  295. g_free (p);
  296. return 0;
  297. }
  298. } else {
  299. GString *errmsg = g_string_new (NULL);
  300. g_string_sprintf (errmsg, _(" Cannot open pipe for reading: %s "), p);
  301. edit_error_dialog (_("Error"), errmsg->str);
  302. g_string_free (errmsg, TRUE);
  303. g_free (p);
  304. return 0;
  305. }
  306. g_free (p);
  307. } else {
  308. int i, file, blocklen;
  309. long current = edit->curs1;
  310. unsigned char *buf;
  311. #ifdef UTF8
  312. mbstate_t mbs;
  313. int bufstart = 0;
  314. memset (&mbs, 0, sizeof (mbs));
  315. #endif /* UTF8 */
  316. if ((file = mc_open (filename, O_RDONLY | O_BINARY)) == -1)
  317. return 0;
  318. buf = g_malloc (TEMP_BUF_LEN);
  319. #ifndef UTF8
  320. while ((blocklen = mc_read (file, (char *) buf, TEMP_BUF_LEN)) > 0) {
  321. for (i = 0; i < blocklen; i++)
  322. edit_insert (edit, buf[i]);
  323. #else /* UTF8 */
  324. while ((blocklen = mc_read (file, (char *) buf + bufstart, TEMP_BUF_LEN - bufstart)) > 0) {
  325. blocklen += bufstart;
  326. bufstart = 0;
  327. for (i = 0; i < blocklen; ) {
  328. mc_wchar_t wc;
  329. int j;
  330. int size = mbrtowc(&wc, (char *)buf + i, blocklen - i, &mbs);
  331. if (size == -2) { /*incomplete char*/
  332. bufstart = blocklen - i;
  333. memcpy(buf, buf+i, bufstart);
  334. i = blocklen;
  335. memset (&mbs, 0, sizeof (mbs));
  336. }
  337. else if (size <= 0) {
  338. #ifdef __STDC_ISO_10646__
  339. edit_insert (edit, BINARY_CHAR_OFFSET + (mc_wchar_t)buf[i]);
  340. #endif
  341. memset (&mbs, 0, sizeof (mbs));
  342. i++; /* skip broken char */
  343. }
  344. else {
  345. edit_insert (edit, wc);
  346. i+=size;
  347. }
  348. }
  349. #endif /* UTF8 */
  350. }
  351. edit_cursor_move (edit, current - edit->curs1);
  352. g_free (buf);
  353. mc_close (file);
  354. if (blocklen)
  355. return 0;
  356. }
  357. return 1;
  358. }
  359. /* Open file and create it if necessary. Return 0 for success, 1 for error. */
  360. static int
  361. check_file_access (WEdit *edit, const char *filename, struct stat *st)
  362. {
  363. int file;
  364. GString *errmsg = (GString *) 0;
  365. /* Try opening an existing file */
  366. file = mc_open (filename, O_NONBLOCK | O_RDONLY | O_BINARY, 0666);
  367. if (file < 0) {
  368. /*
  369. * Try creating the file. O_EXCL prevents following broken links
  370. * and opening existing files.
  371. */
  372. file =
  373. mc_open (filename,
  374. O_NONBLOCK | O_RDONLY | O_BINARY | O_CREAT | O_EXCL,
  375. 0666);
  376. if (file < 0) {
  377. g_string_sprintf (errmsg = g_string_new (NULL),
  378. _(" Cannot open %s for reading "), filename);
  379. goto cleanup;
  380. } else {
  381. /* New file, delete it if it's not modified or saved */
  382. edit->delete_file = 1;
  383. }
  384. }
  385. /* Check what we have opened */
  386. if (mc_fstat (file, st) < 0) {
  387. g_string_sprintf (errmsg = g_string_new (NULL),
  388. _(" Cannot get size/permissions for %s "), filename);
  389. goto cleanup;
  390. }
  391. /* We want to open regular files only */
  392. if (!S_ISREG (st->st_mode)) {
  393. g_string_sprintf (errmsg = g_string_new (NULL),
  394. _(" %s is not a regular file "), filename);
  395. goto cleanup;
  396. }
  397. /*
  398. * Don't delete non-empty files.
  399. * O_EXCL should prevent it, but let's be on the safe side.
  400. */
  401. if (st->st_size > 0) {
  402. edit->delete_file = 0;
  403. }
  404. if (st->st_size >= SIZE_LIMIT) {
  405. g_string_sprintf (errmsg = g_string_new (NULL),
  406. _(" File %s is too large "), filename);
  407. goto cleanup;
  408. }
  409. cleanup:
  410. (void) mc_close (file);
  411. if (errmsg) {
  412. edit_error_dialog (_("Error"), errmsg->str);
  413. g_string_free (errmsg, TRUE);
  414. return 1;
  415. }
  416. return 0;
  417. }
  418. /*
  419. * Open the file and load it into the buffers, either directly or using
  420. * a filter. Return 0 on success, 1 on error.
  421. *
  422. * Fast loading (edit_load_file_fast) is used when the file size is
  423. * known. In this case the data is read into the buffers by blocks.
  424. * If the file size is not known, the data is loaded byte by byte in
  425. * edit_insert_file.
  426. */
  427. static int
  428. edit_load_file (WEdit *edit)
  429. {
  430. #ifndef UTF8
  431. int fast_load = 1;
  432. #else /* UTF8 */
  433. int fast_load = 0; /* can't be used with multibyte characters */
  434. #endif /* UTF8 */
  435. /* Cannot do fast load if a filter is used */
  436. if (edit_find_filter (edit->filename) >= 0)
  437. fast_load = 0;
  438. /*
  439. * VFS may report file size incorrectly, and slow load is not a big
  440. * deal considering overhead in VFS.
  441. */
  442. if (!vfs_file_is_local (edit->filename))
  443. fast_load = 0;
  444. /*
  445. * FIXME: line end translation should disable fast loading as well
  446. * Consider doing fseek() to the end and ftell() for the real size.
  447. */
  448. if (*edit->filename) {
  449. /* If we are dealing with a real file, check that it exists */
  450. if (check_file_access (edit, edit->filename, &edit->stat1))
  451. return 1;
  452. } else {
  453. /* nothing to load */
  454. fast_load = 0;
  455. }
  456. edit_init_buffers (edit);
  457. if (fast_load) {
  458. edit->last_byte = edit->stat1.st_size;
  459. edit_load_file_fast (edit, edit->filename);
  460. /* If fast load was used, the number of lines wasn't calculated */
  461. edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
  462. } else {
  463. edit->last_byte = 0;
  464. if (*edit->filename) {
  465. edit->stack_disable = 1;
  466. if (!edit_insert_file (edit, edit->filename)) {
  467. edit_clean (edit);
  468. return 1;
  469. }
  470. edit->stack_disable = 0;
  471. }
  472. }
  473. return 0;
  474. }
  475. /* Restore saved cursor position in the file */
  476. static void
  477. edit_load_position (WEdit *edit)
  478. {
  479. char *filename;
  480. long line, column;
  481. if (!edit->filename || !*edit->filename)
  482. return;
  483. filename = vfs_canon (edit->filename);
  484. load_file_position (filename, &line, &column);
  485. g_free (filename);
  486. edit_move_to_line (edit, line - 1);
  487. edit->prev_col = column;
  488. edit_move_to_prev_col (edit, edit_bol (edit, edit->curs1));
  489. edit_move_display (edit, line - (edit->num_widget_lines / 2));
  490. edit->charpoint = 0;
  491. }
  492. /* Save cursor position in the file */
  493. static void
  494. edit_save_position (WEdit *edit)
  495. {
  496. char *filename;
  497. if (!edit->filename || !*edit->filename)
  498. return;
  499. filename = vfs_canon (edit->filename);
  500. save_file_position (filename, edit->curs_line + 1, edit->curs_col);
  501. g_free (filename);
  502. }
  503. /* Clean the WEdit stricture except the widget part */
  504. static inline void
  505. edit_purge_widget (WEdit *edit)
  506. {
  507. int len = sizeof (WEdit) - sizeof (Widget);
  508. char *start = (char *) edit + sizeof (Widget);
  509. memset (start, 0, len);
  510. edit->macro_i = -1; /* not recording a macro */
  511. }
  512. #define space_width 1
  513. /*
  514. * Fill in the edit structure. Return NULL on failure. Pass edit as
  515. * NULL to allocate a new structure.
  516. *
  517. * If line is 0, try to restore saved position. Otherwise put the
  518. * cursor on that line and show it in the middle of the screen.
  519. */
  520. WEdit *
  521. edit_init (WEdit *edit, int lines, int columns, const char *filename,
  522. long line)
  523. {
  524. int to_free = 0;
  525. option_auto_syntax = 1; /* Resetting to auto on every invokation */
  526. if (!edit) {
  527. #ifdef ENABLE_NLS
  528. /*
  529. * Expand option_whole_chars_search by national letters using
  530. * current locale
  531. */
  532. static char option_whole_chars_search_buf[256];
  533. if (option_whole_chars_search_buf != option_whole_chars_search) {
  534. size_t i;
  535. size_t len = strlen (option_whole_chars_search);
  536. strcpy (option_whole_chars_search_buf,
  537. option_whole_chars_search);
  538. for (i = 1; i <= sizeof (option_whole_chars_search_buf); i++) {
  539. if (islower (i) && !strchr (option_whole_chars_search, i)) {
  540. option_whole_chars_search_buf[len++] = i;
  541. }
  542. }
  543. option_whole_chars_search_buf[len] = 0;
  544. option_whole_chars_search = option_whole_chars_search_buf;
  545. }
  546. #endif /* ENABLE_NLS */
  547. edit = g_malloc0 (sizeof (WEdit));
  548. to_free = 1;
  549. }
  550. edit_purge_widget (edit);
  551. edit->num_widget_lines = lines;
  552. edit->num_widget_columns = columns;
  553. edit->stat1.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
  554. edit->stat1.st_uid = getuid ();
  555. edit->stat1.st_gid = getgid ();
  556. edit->stat1.st_mtime = 0;
  557. edit->bracket = -1;
  558. edit->force |= REDRAW_PAGE;
  559. edit_set_filename (edit, filename);
  560. edit->stack_size = START_STACK_SIZE;
  561. edit->stack_size_mask = START_STACK_SIZE - 1;
  562. edit->undo_stack = g_malloc ((edit->stack_size + 10) * sizeof (struct action));
  563. if (edit_load_file (edit)) {
  564. /* edit_load_file already gives an error message */
  565. if (to_free)
  566. g_free (edit);
  567. return 0;
  568. }
  569. edit->loading_done = 1;
  570. edit->modified = 0;
  571. edit->locked = 0;
  572. edit_load_syntax (edit, 0, 0);
  573. {
  574. int color;
  575. edit_get_syntax_color (edit, -1, &color);
  576. }
  577. /* load saved cursor position */
  578. if ((line == 0) && option_save_position) {
  579. edit_load_position (edit);
  580. } else {
  581. if (line <= 0)
  582. line = 1;
  583. edit_move_display (edit, line - 1);
  584. edit_move_to_line (edit, line - 1);
  585. }
  586. edit_load_user_map(edit);
  587. return edit;
  588. }
  589. /* Clear the edit struct, freeing everything in it. Return 1 on success */
  590. int
  591. edit_clean (WEdit *edit)
  592. {
  593. int j = 0;
  594. if (!edit)
  595. return 0;
  596. /* a stale lock, remove it */
  597. if (edit->locked)
  598. edit->locked = edit_unlock_file (edit->filename);
  599. /* save cursor position */
  600. if (option_save_position)
  601. edit_save_position (edit);
  602. /* File specified on the mcedit command line and never saved */
  603. if (edit->delete_file)
  604. unlink (edit->filename);
  605. edit_free_syntax_rules (edit);
  606. book_mark_flush (edit, -1);
  607. for (; j <= MAXBUFF; j++) {
  608. g_free (edit->buffers1[j]);
  609. g_free (edit->buffers2[j]);
  610. }
  611. g_free (edit->undo_stack);
  612. g_free (edit->filename);
  613. g_free (edit->dir);
  614. edit_purge_widget (edit);
  615. /* Free temporary strings used in catstrs() */
  616. freestrs ();
  617. return 1;
  618. }
  619. /* returns 1 on success */
  620. int edit_renew (WEdit * edit)
  621. {
  622. int lines = edit->num_widget_lines;
  623. int columns = edit->num_widget_columns;
  624. int retval = 1;
  625. edit_clean (edit);
  626. if (!edit_init (edit, lines, columns, "", 0))
  627. retval = 0;
  628. return retval;
  629. }
  630. /*
  631. * Load a new file into the editor. If it fails, preserve the old file.
  632. * To do it, allocate a new widget, initialize it and, if the new file
  633. * was loaded, copy the data to the old widget.
  634. * Return 1 on success, 0 on failure.
  635. */
  636. int
  637. edit_reload (WEdit *edit, const char *filename)
  638. {
  639. WEdit *e;
  640. int lines = edit->num_widget_lines;
  641. int columns = edit->num_widget_columns;
  642. e = g_malloc0 (sizeof (WEdit));
  643. e->widget = edit->widget;
  644. if (!edit_init (e, lines, columns, filename, 0)) {
  645. g_free (e);
  646. return 0;
  647. }
  648. edit_clean (edit);
  649. memcpy (edit, e, sizeof (WEdit));
  650. g_free (e);
  651. return 1;
  652. }
  653. /*
  654. Recording stack for undo:
  655. The following is an implementation of a compressed stack. Identical
  656. pushes are recorded by a negative prefix indicating the number of times the
  657. same char was pushed. This saves space for repeated curs-left or curs-right
  658. delete etc.
  659. eg:
  660. pushed: stored:
  661. a
  662. b a
  663. b -3
  664. b b
  665. c --> -4
  666. c c
  667. c d
  668. c
  669. d
  670. If the stack long int is 0-255 it represents a normal insert (from a backspace),
  671. 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
  672. of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
  673. set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
  674. position.
  675. The only way the cursor moves or the buffer is changed is through the routines:
  676. insert, backspace, insert_ahead, delete, and cursor_move.
  677. These record the reverse undo movements onto the stack each time they are
  678. called.
  679. Each key press results in a set of actions (insert; delete ...). So each time
  680. a key is pressed the current position of start_display is pushed as
  681. KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
  682. over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
  683. tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
  684. */
  685. void edit_push_action (WEdit * edit, long c,...)
  686. {
  687. unsigned long sp = edit->stack_pointer;
  688. unsigned long spm1;
  689. struct action *t;
  690. mc_wchar_t ch = 0;
  691. if (c == CHAR_INSERT || c == CHAR_INSERT_AHEAD) {
  692. va_list ap;
  693. va_start (ap, c);
  694. ch = va_arg (ap, mc_wint_t);
  695. va_end (ap);
  696. }
  697. /* first enlarge the stack if necessary */
  698. if (sp > edit->stack_size - 10) { /* say */
  699. if (option_max_undo < 256)
  700. option_max_undo = 256;
  701. if (edit->stack_size < (unsigned long) option_max_undo) {
  702. t = g_realloc (edit->undo_stack, (edit->stack_size * 2 + 10) * sizeof (struct action));
  703. if (t) {
  704. edit->undo_stack = t;
  705. edit->stack_size <<= 1;
  706. edit->stack_size_mask = edit->stack_size - 1;
  707. }
  708. }
  709. }
  710. spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask;
  711. if (edit->stack_disable)
  712. return;
  713. #ifdef FAST_MOVE_CURSOR
  714. if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) {
  715. va_list ap;
  716. edit->undo_stack[sp].flags = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT;
  717. edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
  718. va_start (ap, c);
  719. c = -(va_arg (ap, int));
  720. va_end (ap);
  721. } else
  722. #endif /* ! FAST_MOVE_CURSOR */
  723. if (edit->stack_bottom != sp
  724. && spm1 != edit->stack_bottom
  725. && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) {
  726. int d;
  727. mc_wchar_t d_ch;
  728. if (edit->undo_stack[spm1].flags < 0) {
  729. d = edit->undo_stack[(sp - 2) & edit->stack_size_mask].flags;
  730. d_ch = edit->undo_stack[(sp - 2) & edit->stack_size_mask].ch;
  731. if (d == c && d_ch == ch) {
  732. if (edit->undo_stack[spm1].flags > -1000000000) {
  733. if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
  734. edit->undo_stack[spm1].flags--;
  735. return;
  736. }
  737. }
  738. /* #define NO_STACK_CURSMOVE_ANIHILATION */
  739. #ifndef NO_STACK_CURSMOVE_ANIHILATION
  740. else if ((c == CURS_LEFT && d == CURS_RIGHT)
  741. || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
  742. if (edit->undo_stack[spm1].flags == -2)
  743. edit->stack_pointer = spm1;
  744. else
  745. edit->undo_stack[spm1].flags++;
  746. return;
  747. }
  748. #endif
  749. } else {
  750. d = edit->undo_stack[spm1].flags;
  751. d_ch = edit->undo_stack[spm1].ch;
  752. if (d == c && d_ch == ch) {
  753. if (c >= KEY_PRESS)
  754. return; /* --> no need to push multiple do-nothings */
  755. edit->undo_stack[sp].flags = -2;
  756. goto check_bottom;
  757. }
  758. #ifndef NO_STACK_CURSMOVE_ANIHILATION
  759. else if ((c == CURS_LEFT && d == CURS_RIGHT)
  760. || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
  761. edit->stack_pointer = spm1;
  762. return;
  763. }
  764. #endif
  765. }
  766. }
  767. edit->undo_stack[sp].flags = c;
  768. edit->undo_stack[sp].ch = ch;
  769. check_bottom:
  770. edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
  771. /* if the sp wraps round and catches the stack_bottom then erase
  772. * the first set of actions on the stack to make space - by moving
  773. * stack_bottom forward one "key press" */
  774. c = (edit->stack_pointer + 2) & edit->stack_size_mask;
  775. if ((unsigned long) c == edit->stack_bottom ||
  776. (((unsigned long) c + 1) & edit->stack_size_mask) == edit->stack_bottom)
  777. do {
  778. edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask;
  779. } while (edit->undo_stack[edit->stack_bottom].flags < KEY_PRESS && edit->stack_bottom != edit->stack_pointer);
  780. /*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */
  781. if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom].flags < KEY_PRESS)
  782. edit->stack_bottom = edit->stack_pointer = 0;
  783. }
  784. /*
  785. TODO: if the user undos until the stack bottom, and the stack has not wrapped,
  786. then the file should be as it was when he loaded up. Then set edit->modified to 0.
  787. */
  788. static long
  789. pop_action (WEdit * edit, struct action *c)
  790. {
  791. unsigned long sp = edit->stack_pointer;
  792. if (sp == edit->stack_bottom) {
  793. c->flags = STACK_BOTTOM;
  794. return c->flags;
  795. }
  796. sp = (sp - 1) & edit->stack_size_mask;
  797. *c = edit->undo_stack[sp];
  798. if (edit->undo_stack[sp].flags >= 0) {
  799. edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask;
  800. return c->flags;
  801. }
  802. if (sp == edit->stack_bottom) {
  803. return STACK_BOTTOM;
  804. }
  805. *c = edit->undo_stack[(sp - 1) & edit->stack_size_mask];
  806. if (edit->undo_stack[sp].flags == -2) {
  807. edit->stack_pointer = sp;
  808. } else
  809. edit->undo_stack[sp].flags++;
  810. return c->flags;
  811. }
  812. /* is called whenever a modification is made by one of the four routines below */
  813. static inline void edit_modification (WEdit * edit)
  814. {
  815. edit->caches_valid = 0;
  816. edit->screen_modified = 1;
  817. /* raise lock when file modified */
  818. if (!edit->modified && !edit->delete_file)
  819. edit->locked = edit_lock_file (edit->filename);
  820. edit->modified = 1;
  821. }
  822. /*
  823. Basic low level single character buffer alterations and movements at the cursor.
  824. Returns char passed over, inserted or removed.
  825. */
  826. void
  827. edit_insert (WEdit *edit, mc_wchar_t c)
  828. {
  829. /* check if file has grown to large */
  830. if (edit->last_byte >= SIZE_LIMIT)
  831. return;
  832. /* first we must update the position of the display window */
  833. if (edit->curs1 < edit->start_display) {
  834. edit->start_display++;
  835. if (c == '\n')
  836. edit->start_line++;
  837. }
  838. /* Mark file as modified, unless the file hasn't been fully loaded */
  839. if (edit->loading_done) {
  840. edit_modification (edit);
  841. }
  842. /* now we must update some info on the file and check if a redraw is required */
  843. if (c == '\n') {
  844. if (edit->book_mark)
  845. book_mark_inc (edit, edit->curs_line);
  846. edit->curs_line++;
  847. edit->total_lines++;
  848. edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
  849. }
  850. /* save the reverse command onto the undo stack */
  851. edit_push_action (edit, BACKSPACE);
  852. /* update markers */
  853. edit->mark1 += (edit->mark1 > edit->curs1);
  854. edit->mark2 += (edit->mark2 > edit->curs1);
  855. edit->last_get_rule += (edit->last_get_rule > edit->curs1);
  856. /* add a new buffer if we've reached the end of the last one */
  857. if (!(edit->curs1 & M_EDIT_BUF_SIZE))
  858. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] =
  859. g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  860. /* perform the insertion */
  861. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]
  862. [edit->curs1 & M_EDIT_BUF_SIZE] = c;
  863. /* update file length */
  864. edit->last_byte++;
  865. /* update cursor position */
  866. edit->curs1++;
  867. }
  868. /* same as edit_insert and move left */
  869. void edit_insert_ahead (WEdit * edit, mc_wchar_t c)
  870. {
  871. if (edit->last_byte >= SIZE_LIMIT)
  872. return;
  873. if (edit->curs1 < edit->start_display) {
  874. edit->start_display++;
  875. if (c == '\n')
  876. edit->start_line++;
  877. }
  878. edit_modification (edit);
  879. if (c == '\n') {
  880. if (edit->book_mark)
  881. book_mark_inc (edit, edit->curs_line);
  882. edit->total_lines++;
  883. edit->force |= REDRAW_AFTER_CURSOR;
  884. }
  885. edit_push_action (edit, DELCHAR);
  886. edit->mark1 += (edit->mark1 >= edit->curs1);
  887. edit->mark2 += (edit->mark2 >= edit->curs1);
  888. edit->last_get_rule += (edit->last_get_rule >= edit->curs1);
  889. if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
  890. edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  891. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
  892. edit->last_byte++;
  893. edit->curs2++;
  894. }
  895. int edit_delete (WEdit * edit)
  896. {
  897. mc_wint_t p;
  898. if (!edit->curs2)
  899. return 0;
  900. edit->mark1 -= (edit->mark1 > edit->curs1);
  901. edit->mark2 -= (edit->mark2 > edit->curs1);
  902. edit->last_get_rule -= (edit->last_get_rule > edit->curs1);
  903. p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
  904. if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
  905. g_free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
  906. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL;
  907. }
  908. edit->last_byte--;
  909. edit->curs2--;
  910. edit_modification (edit);
  911. if (p == '\n') {
  912. if (edit->book_mark)
  913. book_mark_dec (edit, edit->curs_line);
  914. edit->total_lines--;
  915. edit->force |= REDRAW_AFTER_CURSOR;
  916. }
  917. edit_push_action (edit, CHAR_INSERT_AHEAD, p);
  918. if (edit->curs1 < edit->start_display) {
  919. edit->start_display--;
  920. if (p == '\n')
  921. edit->start_line--;
  922. }
  923. return p;
  924. }
  925. static int
  926. edit_backspace (WEdit * edit)
  927. {
  928. mc_wint_t p;
  929. if (!edit->curs1)
  930. return 0;
  931. edit->mark1 -= (edit->mark1 >= edit->curs1);
  932. edit->mark2 -= (edit->mark2 >= edit->curs1);
  933. edit->last_get_rule -= (edit->last_get_rule >= edit->curs1);
  934. p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] + ((edit->curs1 - 1) & M_EDIT_BUF_SIZE));
  935. if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
  936. g_free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
  937. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
  938. }
  939. edit->last_byte--;
  940. edit->curs1--;
  941. edit_modification (edit);
  942. if (p == '\n') {
  943. if (edit->book_mark)
  944. book_mark_dec (edit, edit->curs_line);
  945. edit->curs_line--;
  946. edit->total_lines--;
  947. edit->force |= REDRAW_AFTER_CURSOR;
  948. }
  949. edit_push_action (edit, CHAR_INSERT, p);
  950. if (edit->curs1 < edit->start_display) {
  951. edit->start_display--;
  952. if (p == '\n')
  953. edit->start_line--;
  954. }
  955. return p;
  956. }
  957. #ifdef FAST_MOVE_CURSOR
  958. static void memqcpy (WEdit * edit, mc_wchar_t *dest, mc_wchar_t *src, int n)
  959. {
  960. unsigned long next;
  961. #ifndef UTF8
  962. while ((next = (unsigned long) memccpy (dest, src, '\n', n))) {
  963. #else /* UTF8 */
  964. while (n) {
  965. next = 0;
  966. while (next < n && src[next]!='\n') next++;
  967. if (next < n) next++;
  968. wmemcpy (dest, src, next)
  969. #endif /* UTF8 */
  970. edit->curs_line--;
  971. next -= (unsigned long) dest;
  972. n -= next;
  973. src += next;
  974. dest += next;
  975. }
  976. }
  977. int
  978. edit_move_backward_lots (WEdit *edit, long increment)
  979. {
  980. int r, s, t;
  981. mc_wchar_t *p;
  982. if (increment > edit->curs1)
  983. increment = edit->curs1;
  984. if (increment <= 0)
  985. return -1;
  986. edit_push_action (edit, CURS_RIGHT_LOTS, increment);
  987. t = r = EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
  988. if (r > increment)
  989. r = increment;
  990. s = edit->curs1 & M_EDIT_BUF_SIZE;
  991. p = 0;
  992. if (s > r) {
  993. memqcpy (edit,
  994. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
  995. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - r,
  996. r);
  997. } else {
  998. if (s) {
  999. memqcpy (edit,
  1000. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t -
  1001. s, edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE], s);
  1002. p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
  1003. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
  1004. }
  1005. memqcpy (edit,
  1006. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
  1007. edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] +
  1008. EDIT_BUF_SIZE - (r - s), r - s);
  1009. }
  1010. increment -= r;
  1011. edit->curs1 -= r;
  1012. edit->curs2 += r;
  1013. if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
  1014. if (p)
  1015. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
  1016. else
  1017. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] =
  1018. g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  1019. } else {
  1020. g_free (p);
  1021. }
  1022. s = edit->curs1 & M_EDIT_BUF_SIZE;
  1023. while (increment) {
  1024. p = 0;
  1025. r = EDIT_BUF_SIZE;
  1026. if (r > increment)
  1027. r = increment;
  1028. t = s;
  1029. if (r < t)
  1030. t = r;
  1031. memqcpy (edit,
  1032. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] +
  1033. EDIT_BUF_SIZE - t,
  1034. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - t,
  1035. t);
  1036. if (r >= s) {
  1037. if (t) {
  1038. p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
  1039. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
  1040. }
  1041. memqcpy (edit,
  1042. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] +
  1043. EDIT_BUF_SIZE - r,
  1044. edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] +
  1045. EDIT_BUF_SIZE - (r - s), r - s);
  1046. }
  1047. increment -= r;
  1048. edit->curs1 -= r;
  1049. edit->curs2 += r;
  1050. if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
  1051. if (p)
  1052. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
  1053. else
  1054. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] =
  1055. g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  1056. } else {
  1057. g_free (p);
  1058. }
  1059. }
  1060. return edit_get_byte (edit, edit->curs1);
  1061. }
  1062. #endif /* ! FAST_MOVE_CURSOR */
  1063. /* moves the cursor right or left: increment positive or negative respectively */
  1064. void edit_cursor_move (WEdit * edit, long increment)
  1065. {
  1066. /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
  1067. int c;
  1068. #ifdef FAST_MOVE_CURSOR
  1069. if (increment < -256) {
  1070. edit->force |= REDRAW_PAGE;
  1071. edit_move_backward_lots (edit, -increment);
  1072. return;
  1073. }
  1074. #endif /* ! FAST_MOVE_CURSOR */
  1075. if (increment < 0) {
  1076. for (; increment < 0; increment++) {
  1077. if (!edit->curs1)
  1078. return;
  1079. edit_push_action (edit, CURS_RIGHT);
  1080. c = edit_get_byte (edit, edit->curs1 - 1);
  1081. if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
  1082. edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  1083. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
  1084. edit->curs2++;
  1085. c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 - 1) & M_EDIT_BUF_SIZE];
  1086. if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
  1087. g_free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
  1088. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
  1089. }
  1090. edit->curs1--;
  1091. if (c == '\n') {
  1092. edit->curs_line--;
  1093. edit->force |= REDRAW_LINE_BELOW;
  1094. }
  1095. }
  1096. } else if (increment > 0) {
  1097. for (; increment > 0; increment--) {
  1098. if (!edit->curs2)
  1099. return;
  1100. edit_push_action (edit, CURS_LEFT);
  1101. c = edit_get_byte (edit, edit->curs1);
  1102. if (!(edit->curs1 & M_EDIT_BUF_SIZE))
  1103. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t));
  1104. edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c;
  1105. edit->curs1++;
  1106. c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
  1107. if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
  1108. g_free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
  1109. edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0;
  1110. }
  1111. edit->curs2--;
  1112. if (c == '\n') {
  1113. edit->curs_line++;
  1114. edit->force |= REDRAW_LINE_ABOVE;
  1115. }
  1116. }
  1117. }
  1118. }
  1119. /* These functions return positions relative to lines */
  1120. /* returns index of last char on line + 1 */
  1121. long edit_eol (WEdit * edit, long current)
  1122. {
  1123. if (current < edit->last_byte) {
  1124. for (;; current++)
  1125. if (edit_get_byte (edit, current) == '\n')
  1126. break;
  1127. } else
  1128. return edit->last_byte;
  1129. return current;
  1130. }
  1131. /* returns index of first char on line */
  1132. long edit_bol (WEdit * edit, long current)
  1133. {
  1134. if (current > 0) {
  1135. for (;; current--)
  1136. if (edit_get_byte (edit, current - 1) == '\n')
  1137. break;
  1138. } else
  1139. return 0;
  1140. return current;
  1141. }
  1142. int edit_count_lines (WEdit * edit, long current, int upto)
  1143. {
  1144. int lines = 0;
  1145. if (upto > edit->last_byte)
  1146. upto = edit->last_byte;
  1147. if (current < 0)
  1148. current = 0;
  1149. while (current < upto)
  1150. if (edit_get_byte (edit, current++) == '\n')
  1151. lines++;
  1152. return lines;
  1153. }
  1154. /* If lines is zero this returns the count of lines from current to upto. */
  1155. /* If upto is zero returns index of lines forward current. */
  1156. long edit_move_forward (WEdit * edit, long current, int lines, long upto)
  1157. {
  1158. if (upto) {
  1159. return edit_count_lines (edit, current, upto);
  1160. } else {
  1161. int next;
  1162. if (lines < 0)
  1163. lines = 0;
  1164. while (lines--) {
  1165. next = edit_eol (edit, current) + 1;
  1166. if (next > edit->last_byte)
  1167. break;
  1168. else
  1169. current = next;
  1170. }
  1171. return current;
  1172. }
  1173. }
  1174. /* Returns offset of 'lines' lines up from current */
  1175. long edit_move_backward (WEdit * edit, long current, int lines)
  1176. {
  1177. if (lines < 0)
  1178. lines = 0;
  1179. current = edit_bol (edit, current);
  1180. while((lines--) && current != 0)
  1181. current = edit_bol (edit, current - 1);
  1182. return current;
  1183. }
  1184. /* If cols is zero this returns the count of columns from current to upto. */
  1185. /* If upto is zero returns index of cols across from current. */
  1186. long edit_move_forward3 (WEdit * edit, long current, int cols, long upto)
  1187. {
  1188. long p, q;
  1189. int col = 0;
  1190. if (upto) {
  1191. q = upto;
  1192. cols = -10;
  1193. } else
  1194. q = edit->last_byte + 2;
  1195. for (col = 0, p = current; p < q; p++) {
  1196. mc_wchar_t c;
  1197. if (cols != -10) {
  1198. if (col == cols)
  1199. return p;
  1200. if (col > cols)
  1201. return p - 1;
  1202. }
  1203. c = edit_get_byte (edit, p);
  1204. if (c == '\t')
  1205. col += TAB_SIZE - col % TAB_SIZE;
  1206. else if (c == '\n') {
  1207. if (upto)
  1208. return col;
  1209. else
  1210. return p;
  1211. } else if (c < 32 || c == 127)
  1212. col += 2; /* Caret notation for control characters */
  1213. else
  1214. col += wcwidth(c);
  1215. }
  1216. return col;
  1217. }
  1218. /* returns the current column position of the cursor */
  1219. int edit_get_col (WEdit * edit)
  1220. {
  1221. return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
  1222. }
  1223. /* Scrolling functions */
  1224. void edit_update_curs_row (WEdit * edit)
  1225. {
  1226. edit->curs_row = edit->curs_line - edit->start_line;
  1227. }
  1228. void edit_update_curs_col (WEdit * edit)
  1229. {
  1230. edit->curs_col = edit_move_forward3(edit, edit_bol(edit, edit->curs1), 0, edit->curs1);
  1231. }
  1232. /*moves the display start position up by i lines */
  1233. void edit_scroll_upward (WEdit * edit, unsigned long i)
  1234. {
  1235. unsigned long lines_above = edit->start_line;
  1236. if (i > lines_above)
  1237. i = lines_above;
  1238. if (i) {
  1239. edit->start_line -= i;
  1240. edit->start_display = edit_move_backward (edit, edit->start_display, i);
  1241. edit->force |= REDRAW_PAGE;
  1242. edit->force &= (0xfff - REDRAW_CHAR_ONLY);
  1243. }
  1244. edit_update_curs_row (edit);
  1245. }
  1246. /* returns 1 if could scroll, 0 otherwise */
  1247. void edit_scroll_downward (WEdit * edit, int i)
  1248. {
  1249. int lines_below;
  1250. lines_below = edit->total_lines - edit->start_line - (edit->num_widget_lines - 1);
  1251. if (lines_below > 0) {
  1252. if (i > lines_below)
  1253. i = lines_below;
  1254. edit->start_line += i;
  1255. edit->start_display = edit_move_forward (edit, edit->start_display, i, 0);
  1256. edit->force |= REDRAW_PAGE;
  1257. edit->force &= (0xfff - REDRAW_CHAR_ONLY);
  1258. }
  1259. edit_update_curs_row (edit);
  1260. }
  1261. void edit_scroll_right (WEdit * edit, int i)
  1262. {
  1263. edit->force |= REDRAW_PAGE;
  1264. edit->force &= (0xfff - REDRAW_CHAR_ONLY);
  1265. edit->start_col -= i;
  1266. }
  1267. void edit_scroll_left (WEdit * edit, int i)
  1268. {
  1269. if (edit->start_col) {
  1270. edit->start_col += i;
  1271. if (edit->start_col > 0)
  1272. edit->start_col = 0;
  1273. edit->force |= REDRAW_PAGE;
  1274. edit->force &= (0xfff - REDRAW_CHAR_ONLY);
  1275. }
  1276. }
  1277. /* high level cursor movement commands */
  1278. static int is_in_indent (WEdit *edit)
  1279. {
  1280. long p = edit_bol (edit, edit->curs1);
  1281. while (p < edit->curs1)
  1282. if (!strchr (" \t", edit_get_byte (edit, p++)))
  1283. return 0;
  1284. return 1;
  1285. }
  1286. static int left_of_four_spaces (WEdit *edit);
  1287. void
  1288. edit_move_to_prev_col (WEdit * edit, long p)
  1289. {
  1290. edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->prev_col, 0) - edit->curs1);
  1291. if (is_in_indent (edit) && option_fake_half_tabs) {
  1292. edit_update_curs_col (edit);
  1293. if (space_width)
  1294. if (edit->curs_col % (HALF_TAB_SIZE * space_width)) {
  1295. int q = edit->curs_col;
  1296. edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width));
  1297. p = edit_bol (edit, edit->curs1);
  1298. edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->curs_col, 0) - edit->curs1);
  1299. if (!left_of_four_spaces (edit))
  1300. edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1);
  1301. }
  1302. }
  1303. }
  1304. /* move i lines */
  1305. void edit_move_up (WEdit * edit, unsigned long i, int scroll)
  1306. {
  1307. unsigned long p, l = edit->curs_line;
  1308. if (i > l)
  1309. i = l;
  1310. if (i) {
  1311. if (i > 1)
  1312. edit->force |= REDRAW_PAGE;
  1313. if (scroll)
  1314. edit_scroll_upward (edit, i);
  1315. p = edit_bol (edit, edit->curs1);
  1316. edit_cursor_move (edit, (p = edit_move_backward (edit, p, i)) - edit->curs1);
  1317. edit_move_to_prev_col (edit, p);
  1318. edit->search_start = edit->curs1;
  1319. edit->found_len = 0;
  1320. }
  1321. }
  1322. static int
  1323. is_blank (WEdit *edit, long offset)
  1324. {
  1325. long s, f;
  1326. mc_wchar_t c;
  1327. s = edit_bol (edit, offset);
  1328. f = edit_eol (edit, offset) - 1;
  1329. while (s <= f) {
  1330. c = edit_get_byte (edit, s++);
  1331. #ifndef UTF8
  1332. if (!isspace (c))
  1333. #else
  1334. if (!iswspace (c))
  1335. #endif /* UTF8 */
  1336. return 0;
  1337. }
  1338. return 1;
  1339. }
  1340. /* returns the offset of line i */
  1341. static long
  1342. edit_find_line (WEdit *edit, int line)
  1343. {
  1344. int i, j = 0;
  1345. int m = 2000000000;
  1346. if (!edit->caches_valid) {
  1347. for (i = 0; i < N_LINE_CACHES; i++)
  1348. edit->line_numbers[i] = edit->line_offsets[i] = 0;
  1349. /* three offsets that we *know* are line 0 at 0 and these two: */
  1350. edit->line_numbers[1] = edit->curs_line;
  1351. edit->line_offsets[1] = edit_bol (edit, edit->curs1);
  1352. edit->line_numbers[2] = edit->total_lines;
  1353. edit->line_offsets[2] = edit_bol (edit, edit->last_byte);
  1354. edit->caches_valid = 1;
  1355. }
  1356. if (line >= edit->total_lines)
  1357. return edit->line_offsets[2];
  1358. if (line <= 0)
  1359. return 0;
  1360. /* find the closest known point */
  1361. for (i = 0; i < N_LINE_CACHES; i++) {
  1362. int n;
  1363. n = abs (edit->line_numbers[i] - line);
  1364. if (n < m) {
  1365. m = n;
  1366. j = i;
  1367. }
  1368. }
  1369. if (m == 0)
  1370. return edit->line_offsets[j]; /* know the offset exactly */
  1371. if (m == 1 && j >= 3)
  1372. i = j; /* one line different - caller might be looping, so stay in this cache */
  1373. else
  1374. i = 3 + (rand () % (N_LINE_CACHES - 3));
  1375. if (line > edit->line_numbers[j])
  1376. edit->line_offsets[i] = edit_move_forward (edit, edit->line_offsets[j], line - edit->line_numbers[j], 0);
  1377. else
  1378. edit->line_offsets[i] = edit_move_backward (edit, edit->line_offsets[j], edit->line_numbers[j] - line);
  1379. edit->line_numbers[i] = line;
  1380. return edit->line_offsets[i];
  1381. }
  1382. int line_is_blank (WEdit * edit, long line)
  1383. {
  1384. return is_blank (edit, edit_find_line (edit, line));
  1385. }
  1386. /* moves up until a blank line is reached, or until just
  1387. before a non-blank line is reached */
  1388. static void edit_move_up_paragraph (WEdit * edit, int scroll)
  1389. {
  1390. int i;
  1391. if (edit->curs_line <= 1) {
  1392. i = 0;
  1393. } else {
  1394. if (line_is_blank (edit, edit->curs_line)) {
  1395. if (line_is_blank (edit, edit->curs_line - 1)) {
  1396. for (i = edit->curs_line - 1; i; i--)
  1397. if (!line_is_blank (edit, i)) {
  1398. i++;
  1399. break;
  1400. }
  1401. } else {
  1402. for (i = edit->curs_line - 1; i; i--)
  1403. if (line_is_blank (edit, i))
  1404. break;
  1405. }
  1406. } else {
  1407. for (i = edit->curs_line - 1; i; i--)
  1408. if (line_is_blank (edit, i))
  1409. break;
  1410. }
  1411. }
  1412. edit_move_up (edit, edit->curs_line - i, scroll);
  1413. }
  1414. /* move i lines */
  1415. void edit_move_down (WEdit * edit, int i, int scroll)
  1416. {
  1417. long p, l = edit->total_lines - edit->curs_line;
  1418. if (i > l)
  1419. i = l;
  1420. if (i) {
  1421. if (i > 1)
  1422. edit->force |= REDRAW_PAGE;
  1423. if (scroll)
  1424. edit_scroll_downward (edit, i);
  1425. p = edit_bol (edit, edit->curs1);
  1426. edit_cursor_move (edit, (p = edit_move_forward (edit, p, i, 0)) - edit->curs1);
  1427. edit_move_to_prev_col (edit, p);
  1428. edit->search_start = edit->curs1;
  1429. edit->found_len = 0;
  1430. }
  1431. }
  1432. /* moves down until a blank line is reached, or until just
  1433. before a non-blank line is reached */
  1434. static void edit_move_down_paragraph (WEdit * edit, int scroll)
  1435. {
  1436. int i;
  1437. if (edit->curs_line >= edit->total_lines - 1) {
  1438. i = edit->total_lines;
  1439. } else {
  1440. if (line_is_blank (edit, edit->curs_line)) {
  1441. if (line_is_blank (edit, edit->curs_line + 1)) {
  1442. for (i = edit->curs_line + 1; i; i++)
  1443. if (!line_is_blank (edit, i) || i > edit->total_lines) {
  1444. i--;
  1445. break;
  1446. }
  1447. } else {
  1448. for (i = edit->curs_line + 1; i; i++)
  1449. if (line_is_blank (edit, i) || i >= edit->total_lines)
  1450. break;
  1451. }
  1452. } else {
  1453. for (i = edit->curs_line + 1; i; i++)
  1454. if (line_is_blank (edit, i) || i >= edit->total_lines)
  1455. break;
  1456. }
  1457. }
  1458. edit_move_down (edit, i - edit->curs_line, scroll);
  1459. }
  1460. static void edit_begin_page (WEdit *edit)
  1461. {
  1462. edit_update_curs_row (edit);
  1463. edit_move_up (edit, edit->curs_row, 0);
  1464. }
  1465. static void edit_end_page (WEdit *edit)
  1466. {
  1467. edit_update_curs_row (edit);
  1468. edit_move_down (edit, edit->num_widget_lines - edit->curs_row - 1, 0);
  1469. }
  1470. /* goto beginning of text */
  1471. static void edit_move_to_top (WEdit * edit)
  1472. {
  1473. if (edit->curs_line) {
  1474. edit_cursor_move (edit, -edit->curs1);
  1475. edit_move_to_prev_col (edit, 0);
  1476. edit->force |= REDRAW_PAGE;
  1477. edit->search_start = 0;
  1478. edit_update_curs_row(edit);
  1479. }
  1480. }
  1481. /* goto end of text */
  1482. static void edit_move_to_bottom (WEdit * edit)
  1483. {
  1484. if (edit->curs_line < edit->total_lines) {
  1485. edit_cursor_move (edit, edit->curs2);
  1486. edit->start_display = edit->last_byte;
  1487. edit->start_line = edit->total_lines;
  1488. edit_update_curs_row(edit);
  1489. edit_scroll_upward (edit, edit->num_widget_lines - 1);
  1490. edit->force |= REDRAW_PAGE;
  1491. }
  1492. }
  1493. /* goto beginning of line */
  1494. static void edit_cursor_to_bol (WEdit * edit)
  1495. {
  1496. edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
  1497. edit->search_start = edit->curs1;
  1498. edit->prev_col = edit_get_col (edit);
  1499. }
  1500. /* goto end of line */
  1501. static void edit_cursor_to_eol (WEdit * edit)
  1502. {
  1503. edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1);
  1504. edit->search_start = edit->curs1;
  1505. edit->prev_col = edit_get_col (edit);
  1506. }
  1507. /* move cursor to line 'line' */
  1508. void edit_move_to_line (WEdit * e, long line)
  1509. {
  1510. if(line < e->curs_line)
  1511. edit_move_up (e, e->curs_line - line, 0);
  1512. else
  1513. edit_move_down (e, line - e->curs_line, 0);
  1514. edit_scroll_screen_over_cursor (e);
  1515. }
  1516. /* scroll window so that first visible line is 'line' */
  1517. void edit_move_display (WEdit * e, long line)
  1518. {
  1519. if(line < e->start_line)
  1520. edit_scroll_upward (e, e->start_line - line);
  1521. else
  1522. edit_scroll_downward (e, line - e->start_line);
  1523. }
  1524. /* save markers onto undo stack */
  1525. void edit_push_markers (WEdit * edit)
  1526. {
  1527. edit_push_action (edit, MARK_1 + edit->mark1);
  1528. edit_push_action (edit, MARK_2 + edit->mark2);
  1529. }
  1530. void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2)
  1531. {
  1532. edit->mark1 = m1;
  1533. edit->mark2 = m2;
  1534. edit->column1 = c1;
  1535. edit->column2 = c2;
  1536. }
  1537. /* highlight marker toggle */
  1538. void edit_mark_cmd (WEdit * edit, int unmark)
  1539. {
  1540. edit_push_markers (edit);
  1541. if (unmark) {
  1542. edit_set_markers (edit, 0, 0, 0, 0);
  1543. edit->force |= REDRAW_PAGE;
  1544. } else {
  1545. if (edit->mark2 >= 0) {
  1546. edit_set_markers (edit, edit->curs1, -1, edit->curs_col, edit->curs_col);
  1547. edit->force |= REDRAW_PAGE;
  1548. } else
  1549. edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1, edit->curs_col);
  1550. }
  1551. }
  1552. static unsigned long
  1553. my_type_of (int c)
  1554. {
  1555. int x, r = 0;
  1556. const char *p, *q;
  1557. const char option_chars_move_whole_word[] =
  1558. "!=&|<>^~ !:;, !'!`!.?!\"!( !) !Aa0 !+-*/= |<> ![ !] !\\#! ";
  1559. if (!c)
  1560. return 0;
  1561. if (c == '!') {
  1562. if (*option_chars_move_whole_word == '!')
  1563. return 2;
  1564. return 0x80000000UL;
  1565. }
  1566. #ifndef UTF8
  1567. if (isupper (c))
  1568. c = 'A';
  1569. else if (islower (c))
  1570. c = 'a';
  1571. else if (isalpha (c))
  1572. c = 'a';
  1573. else if (isdigit (c))
  1574. c = '0';
  1575. else if (isspace (c))
  1576. c = ' ';
  1577. #else
  1578. if (iswupper (c))
  1579. c = 'A';
  1580. else if (iswlower (c))
  1581. c = 'a';
  1582. else if (iswalpha (c))
  1583. c = 'a';
  1584. else if (iswdigit (c))
  1585. c = '0';
  1586. else if (iswspace (c))
  1587. c = ' ';
  1588. #endif /* UTF8 */
  1589. q = strchr (option_chars_move_whole_word, c);
  1590. if (!q)
  1591. return 0xFFFFFFFFUL;
  1592. do {
  1593. for (x = 1, p = option_chars_move_whole_word; p < q; p++)
  1594. if (*p == '!')
  1595. x <<= 1;
  1596. r |= x;
  1597. } while ((q = strchr (q + 1, c)));
  1598. return r;
  1599. }
  1600. static void
  1601. edit_left_word_move (WEdit *edit, int s)
  1602. {
  1603. for (;;) {
  1604. int c1, c2;
  1605. edit_cursor_move (edit, -1);
  1606. if (!edit->curs1)
  1607. break;
  1608. c1 = edit_get_byte (edit, edit->curs1 - 1);
  1609. c2 = edit_get_byte (edit, edit->curs1);
  1610. if (!(my_type_of (c1) & my_type_of (c2)))
  1611. break;
  1612. #ifndef UTF8
  1613. if (isspace (c1) && !isspace (c2))
  1614. #else
  1615. if (iswspace (c1) && !iswspace (c2))
  1616. #endif /* UTF8 */
  1617. break;
  1618. if (s)
  1619. #ifndef UTF8
  1620. if (!isspace (c1) && isspace (c2))
  1621. #else
  1622. if (!iswspace (c1) && iswspace (c2))
  1623. #endif /* UTF8 */
  1624. break;
  1625. }
  1626. }
  1627. static void edit_left_word_move_cmd (WEdit * edit)
  1628. {
  1629. edit_left_word_move (edit, 0);
  1630. edit->force |= REDRAW_PAGE;
  1631. }
  1632. static void
  1633. edit_right_word_move (WEdit *edit, int s)
  1634. {
  1635. for (;;) {
  1636. int c1, c2;
  1637. edit_cursor_move (edit, 1);
  1638. if (edit->curs1 >= edit->last_byte)
  1639. break;
  1640. c1 = edit_get_byte (edit, edit->curs1 - 1);
  1641. c2 = edit_get_byte (edit, edit->curs1);
  1642. if (!(my_type_of (c1) & my_type_of (c2)))
  1643. break;
  1644. #ifndef UTF8
  1645. if (isspace (c1) && !isspace (c2))
  1646. #else
  1647. if (iswspace (c1) && !iswspace (c2))
  1648. #endif /* UTF8 */
  1649. break;
  1650. if (s)
  1651. #ifndef UTF8
  1652. if (!isspace (c1) && isspace (c2))
  1653. #else
  1654. if (!iswspace (c1) && iswspace (c2))
  1655. #endif /* UTF8 */
  1656. break;
  1657. }
  1658. }
  1659. static void edit_right_word_move_cmd (WEdit * edit)
  1660. {
  1661. edit_right_word_move (edit, 0);
  1662. edit->force |= REDRAW_PAGE;
  1663. }
  1664. static void edit_right_delete_word (WEdit * edit)
  1665. {
  1666. int c1, c2;
  1667. for (;;) {
  1668. if (edit->curs1 >= edit->last_byte)
  1669. break;
  1670. c1 = edit_delete (edit);
  1671. c2 = edit_get_byte (edit, edit->curs1);
  1672. #ifndef UTF8
  1673. if ((isspace (c1) == 0) != (isspace (c2) == 0))
  1674. #else
  1675. if ((iswspace (c1) == 0) != (iswspace (c2) == 0))
  1676. #endif /* UTF8 */
  1677. break;
  1678. if (!(my_type_of (c1) & my_type_of (c2)))
  1679. break;
  1680. }
  1681. }
  1682. static void edit_left_delete_word (WEdit * edit)
  1683. {
  1684. int c1, c2;
  1685. for (;;) {
  1686. if (edit->curs1 <= 0)
  1687. break;
  1688. c1 = edit_backspace (edit);
  1689. c2 = edit_get_byte (edit, edit->curs1 - 1);
  1690. #ifndef UTF8
  1691. if ((isspace (c1) == 0) != (isspace (c2) == 0))
  1692. #else
  1693. if ((iswspace (c1) == 0) != (iswspace (c2) == 0))
  1694. #endif /* UTF8 */
  1695. break;
  1696. if (!(my_type_of (c1) & my_type_of (c2)))
  1697. break;
  1698. }
  1699. }
  1700. /*
  1701. the start column position is not recorded, and hence does not
  1702. undo as it happed. But who would notice.
  1703. */
  1704. static void
  1705. edit_do_undo (WEdit * edit)
  1706. {
  1707. struct action ac;
  1708. long count = 0;
  1709. edit->stack_disable = 1; /* don't record undo's onto undo stack! */
  1710. while (pop_action (edit, &ac) < KEY_PRESS) {
  1711. switch ((int) ac.flags) {
  1712. case STACK_BOTTOM:
  1713. goto done_undo;
  1714. case CURS_RIGHT:
  1715. edit_cursor_move (edit, 1);
  1716. break;
  1717. case CURS_LEFT:
  1718. edit_cursor_move (edit, -1);
  1719. break;
  1720. case BACKSPACE:
  1721. edit_backspace (edit);
  1722. break;
  1723. case DELCHAR:
  1724. edit_delete (edit);
  1725. break;
  1726. case COLUMN_ON:
  1727. column_highlighting = 1;
  1728. break;
  1729. case COLUMN_OFF:
  1730. column_highlighting = 0;
  1731. break;
  1732. case CHAR_INSERT:
  1733. edit_insert (edit, ac.ch);
  1734. break;
  1735. case CHAR_INSERT_AHEAD:
  1736. edit_insert_ahead (edit, ac.ch);
  1737. break;
  1738. }
  1739. if (ac.flags >= MARK_1 - 2 && ac.flags < MARK_2 - 2) {
  1740. edit->mark1 = ac.flags - MARK_1;
  1741. edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1);
  1742. } else if (ac.flags >= MARK_2 - 2 && ac.flags < KEY_PRESS) {
  1743. edit->mark2 = ac.flags - MARK_2;
  1744. edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2);
  1745. }
  1746. if (count++)
  1747. edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
  1748. }
  1749. if (edit->start_display > ac.flags - KEY_PRESS) {
  1750. edit->start_line -= edit_count_lines (edit, ac.flags - KEY_PRESS, edit->start_display);
  1751. edit->force |= REDRAW_PAGE;
  1752. } else if (edit->start_display < ac.flags - KEY_PRESS) {
  1753. edit->start_line += edit_count_lines (edit, edit->start_display, ac.flags - KEY_PRESS);
  1754. edit->force |= REDRAW_PAGE;
  1755. }
  1756. edit->start_display = ac.flags - KEY_PRESS; /* see push and pop above */
  1757. edit_update_curs_row (edit);
  1758. done_undo:;
  1759. edit->stack_disable = 0;
  1760. }
  1761. static void edit_delete_to_line_end (WEdit * edit)
  1762. {
  1763. while (edit_get_byte (edit, edit->curs1) != '\n') {
  1764. if (!edit->curs2)
  1765. break;
  1766. edit_delete (edit);
  1767. }
  1768. }
  1769. static void edit_delete_to_line_begin (WEdit * edit)
  1770. {
  1771. while (edit_get_byte (edit, edit->curs1 - 1) != '\n') {
  1772. if (!edit->curs1)
  1773. break;
  1774. edit_backspace (edit);
  1775. }
  1776. }
  1777. void
  1778. edit_delete_line (WEdit *edit)
  1779. {
  1780. /*
  1781. * Delete right part of the line.
  1782. * Note that edit_get_byte() returns '\n' when byte position is
  1783. * beyond EOF.
  1784. */
  1785. while (edit_get_byte (edit, edit->curs1) != '\n') {
  1786. (void) edit_delete (edit);
  1787. }
  1788. /*
  1789. * Delete '\n' char.
  1790. * Note that edit_delete() will not corrupt anything if called while
  1791. * cursor position is EOF.
  1792. */
  1793. (void) edit_delete (edit);
  1794. /*
  1795. * Delete left part of the line.
  1796. * Note, that edit_get_byte() returns '\n' when byte position is < 0.
  1797. */
  1798. while (edit_get_byte (edit, edit->curs1 - 1) != '\n') {
  1799. (void) edit_backspace (edit);
  1800. };
  1801. }
  1802. static void insert_spaces_tab (WEdit * edit, int half)
  1803. {
  1804. int i;
  1805. edit_update_curs_col (edit);
  1806. i = ((edit->curs_col / (option_tab_spacing * space_width / (half + 1))) + 1) * (option_tab_spacing * space_width / (half + 1)) - edit->curs_col;
  1807. while (i > 0) {
  1808. edit_insert (edit, ' ');
  1809. i -= space_width;
  1810. }
  1811. }
  1812. static int is_aligned_on_a_tab (WEdit * edit)
  1813. {
  1814. edit_update_curs_col (edit);
  1815. if ((edit->curs_col % (TAB_SIZE * space_width)) && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width))
  1816. return 0; /* not alligned on a tab */
  1817. return 1;
  1818. }
  1819. static int right_of_four_spaces (WEdit *edit)
  1820. {
  1821. int i, ch = 0;
  1822. for (i = 1; i <= HALF_TAB_SIZE; i++)
  1823. ch |= edit_get_byte (edit, edit->curs1 - i);
  1824. if (ch == ' ')
  1825. return is_aligned_on_a_tab (edit);
  1826. return 0;
  1827. }
  1828. static int left_of_four_spaces (WEdit *edit)
  1829. {
  1830. int i, ch = 0;
  1831. for (i = 0; i < HALF_TAB_SIZE; i++)
  1832. ch |= edit_get_byte (edit, edit->curs1 + i);
  1833. if (ch == ' ')
  1834. return is_aligned_on_a_tab (edit);
  1835. return 0;
  1836. }
  1837. int edit_indent_width (WEdit * edit, long p)
  1838. {
  1839. long q = p;
  1840. while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */
  1841. q++;
  1842. return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */
  1843. }
  1844. void edit_insert_indent (WEdit * edit, int indent)
  1845. {
  1846. if (!option_fill_tabs_with_spaces) {
  1847. while (indent >= TAB_SIZE) {
  1848. edit_insert (edit, '\t');
  1849. indent -= TAB_SIZE;
  1850. }
  1851. }
  1852. while (indent-- > 0)
  1853. edit_insert (edit, ' ');
  1854. }
  1855. static void
  1856. edit_auto_indent (WEdit * edit)
  1857. {
  1858. long p;
  1859. char c;
  1860. p = edit->curs1;
  1861. /* use the previous line as a template */
  1862. p = edit_move_backward (edit, p, 1);
  1863. /* copy the leading whitespace of the line */
  1864. for (;;) { /* no range check - the line _is_ \n-terminated */
  1865. c = edit_get_byte (edit, p++);
  1866. if (c != ' ' && c != '\t')
  1867. break;
  1868. edit_insert (edit, c);
  1869. }
  1870. }
  1871. static void edit_double_newline (WEdit * edit)
  1872. {
  1873. edit_insert (edit, '\n');
  1874. if (edit_get_byte (edit, edit->curs1) == '\n')
  1875. return;
  1876. if (edit_get_byte (edit, edit->curs1 - 2) == '\n')
  1877. return;
  1878. edit->force |= REDRAW_PAGE;
  1879. edit_insert (edit, '\n');
  1880. }
  1881. static void edit_tab_cmd (WEdit * edit)
  1882. {
  1883. int i;
  1884. if (option_fake_half_tabs) {
  1885. if (is_in_indent (edit)) {
  1886. /*insert a half tab (usually four spaces) unless there is a
  1887. half tab already behind, then delete it and insert a
  1888. full tab. */
  1889. if (!option_fill_tabs_with_spaces && right_of_four_spaces (edit)) {
  1890. for (i = 1; i <= HALF_TAB_SIZE; i++)
  1891. edit_backspace (edit);
  1892. edit_insert (edit, '\t');
  1893. } else {
  1894. insert_spaces_tab (edit, 1);
  1895. }
  1896. return;
  1897. }
  1898. }
  1899. if (option_fill_tabs_with_spaces) {
  1900. insert_spaces_tab (edit, 0);
  1901. } else {
  1902. edit_insert (edit, '\t');
  1903. }
  1904. return;
  1905. }
  1906. static void check_and_wrap_line (WEdit * edit)
  1907. {
  1908. int curs, c;
  1909. if (!option_typewriter_wrap)
  1910. return;
  1911. edit_update_curs_col (edit);
  1912. if (edit->curs_col < option_word_wrap_line_length)
  1913. return;
  1914. curs = edit->curs1;
  1915. for (;;) {
  1916. curs--;
  1917. c = edit_get_byte (edit, curs);
  1918. if (c == '\n' || curs <= 0) {
  1919. edit_insert (edit, '\n');
  1920. return;
  1921. }
  1922. if (c == ' ' || c == '\t') {
  1923. int current = edit->curs1;
  1924. edit_cursor_move (edit, curs - edit->curs1 + 1);
  1925. edit_insert (edit, '\n');
  1926. edit_cursor_move (edit, current - edit->curs1 + 1);
  1927. return;
  1928. }
  1929. }
  1930. }
  1931. static void edit_execute_macro (WEdit *edit, struct macro macro[], int n);
  1932. void edit_push_key_press (WEdit * edit)
  1933. {
  1934. edit_push_action (edit, KEY_PRESS + edit->start_display);
  1935. if (edit->mark2 == -1)
  1936. edit_push_action (edit, MARK_1 + edit->mark1);
  1937. }
  1938. /* this find the matching bracket in either direction, and sets edit->bracket */
  1939. static long edit_get_bracket (WEdit * edit, int in_screen, unsigned long furthest_bracket_search)
  1940. {
  1941. const char * const b = "{}{[][()(", *p;
  1942. int i = 1, a, inc = -1, c, d, n = 0;
  1943. unsigned long j = 0;
  1944. long q;
  1945. edit_update_curs_row (edit);
  1946. c = edit_get_byte (edit, edit->curs1);
  1947. p = strchr (b, c);
  1948. /* no limit */
  1949. if (!furthest_bracket_search)
  1950. furthest_bracket_search--;
  1951. /* not on a bracket at all */
  1952. if (!p)
  1953. return -1;
  1954. /* the matching bracket */
  1955. d = p[1];
  1956. /* going left or right? */
  1957. if (strchr ("{[(", c))
  1958. inc = 1;
  1959. for (q = edit->curs1 + inc;; q += inc) {
  1960. /* out of buffer? */
  1961. if (q >= edit->last_byte || q < 0)
  1962. break;
  1963. a = edit_get_byte (edit, q);
  1964. /* don't want to eat CPU */
  1965. if (j++ > furthest_bracket_search)
  1966. break;
  1967. /* out of screen? */
  1968. if (in_screen) {
  1969. if (q < edit->start_display)
  1970. break;
  1971. /* count lines if searching downward */
  1972. if (inc > 0 && a == '\n')
  1973. if (n++ >= edit->num_widget_lines - edit->curs_row) /* out of screen */
  1974. break;
  1975. }
  1976. /* count bracket depth */
  1977. i += (a == c) - (a == d);
  1978. /* return if bracket depth is zero */
  1979. if (!i)
  1980. return q;
  1981. }
  1982. /* no match */
  1983. return -1;
  1984. }
  1985. static long last_bracket = -1;
  1986. void edit_find_bracket (WEdit * edit)
  1987. {
  1988. edit->bracket = edit_get_bracket (edit, 1, 10000);
  1989. if (last_bracket != edit->bracket)
  1990. edit->force |= REDRAW_PAGE;
  1991. last_bracket = edit->bracket;
  1992. }
  1993. static void edit_goto_matching_bracket (WEdit *edit)
  1994. {
  1995. long q;
  1996. q = edit_get_bracket (edit, 0, 0);
  1997. if (q < 0)
  1998. return;
  1999. edit->bracket = edit->curs1;
  2000. edit->force |= REDRAW_PAGE;
  2001. edit_cursor_move (edit, q - edit->curs1);
  2002. }
  2003. /*
  2004. * This executes a command as though the user initiated it through a key
  2005. * press. Callback with WIDGET_KEY as a message calls this after
  2006. * translating the key press. This function can be used to pass any
  2007. * command to the editor. Note that the screen wouldn't update
  2008. * automatically. Either of command or char_for_insertion must be
  2009. * passed as -1. Commands are executed, and char_for_insertion is
  2010. * inserted at the cursor.
  2011. */
  2012. void edit_execute_key_command (WEdit *edit, int command, mc_wint_t char_for_insertion)
  2013. {
  2014. if (command == CK_Begin_Record_Macro) {
  2015. edit->macro_i = 0;
  2016. edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
  2017. return;
  2018. }
  2019. if (command == CK_End_Record_Macro && edit->macro_i != -1) {
  2020. edit->force |= REDRAW_COMPLETELY;
  2021. edit_save_macro_cmd (edit, edit->macro, edit->macro_i);
  2022. edit->macro_i = -1;
  2023. return;
  2024. }
  2025. if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1) {
  2026. edit->macro[edit->macro_i].command = command;
  2027. edit->macro[edit->macro_i++].ch = char_for_insertion;
  2028. }
  2029. /* record the beginning of a set of editing actions initiated by a key press */
  2030. if (command != CK_Undo && command != CK_Ext_Mode)
  2031. edit_push_key_press (edit);
  2032. edit_execute_cmd (edit, command, char_for_insertion);
  2033. if (column_highlighting)
  2034. edit->force |= REDRAW_PAGE;
  2035. }
  2036. static const char * const shell_cmd[] = SHELL_COMMANDS_i;
  2037. /*
  2038. This executes a command at a lower level than macro recording.
  2039. It also does not push a key_press onto the undo stack. This means
  2040. that if it is called many times, a single undo command will undo
  2041. all of them. It also does not check for the Undo command.
  2042. */
  2043. void
  2044. edit_execute_cmd (WEdit *edit, int command, mc_wint_t char_for_insertion)
  2045. {
  2046. edit->force |= REDRAW_LINE;
  2047. /* The next key press will unhighlight the found string, so update
  2048. * the whole page */
  2049. if (edit->found_len || column_highlighting)
  2050. edit->force |= REDRAW_PAGE;
  2051. if (command / 100 == 6) { /* a highlight command like shift-arrow */
  2052. column_highlighting = 0;
  2053. if (!edit->highlight
  2054. || (edit->mark2 != -1 && edit->mark1 != edit->mark2)) {
  2055. edit_mark_cmd (edit, 1); /* clear */
  2056. edit_mark_cmd (edit, 0); /* marking on */
  2057. }
  2058. edit->highlight = 1;
  2059. } else { /* any other command */
  2060. if (edit->highlight)
  2061. edit_mark_cmd (edit, 0); /* clear */
  2062. edit->highlight = 0;
  2063. }
  2064. /* first check for undo */
  2065. if (command == CK_Undo) {
  2066. edit_do_undo (edit);
  2067. edit->found_len = 0;
  2068. edit->prev_col = edit_get_col (edit);
  2069. edit->search_start = edit->curs1;
  2070. return;
  2071. }
  2072. /* An ordinary key press */
  2073. if (char_for_insertion != (mc_wint_t) -1) {
  2074. if (edit->overwrite) {
  2075. if (edit_get_byte (edit, edit->curs1) != '\n')
  2076. edit_delete (edit);
  2077. }
  2078. edit_insert (edit, char_for_insertion);
  2079. if (option_auto_para_formatting) {
  2080. format_paragraph (edit, 0);
  2081. edit->force |= REDRAW_PAGE;
  2082. } else
  2083. check_and_wrap_line (edit);
  2084. edit->found_len = 0;
  2085. edit->prev_col = edit_get_col (edit);
  2086. edit->search_start = edit->curs1;
  2087. edit_find_bracket (edit);
  2088. return;
  2089. }
  2090. switch (command) {
  2091. case CK_Begin_Page:
  2092. case CK_End_Page:
  2093. case CK_Begin_Page_Highlight:
  2094. case CK_End_Page_Highlight:
  2095. case CK_Word_Left:
  2096. case CK_Word_Right:
  2097. case CK_Up:
  2098. case CK_Down:
  2099. case CK_Word_Left_Highlight:
  2100. case CK_Word_Right_Highlight:
  2101. case CK_Up_Highlight:
  2102. case CK_Down_Highlight:
  2103. if (edit->mark2 == -1)
  2104. break; /*marking is following the cursor: may need to highlight a whole line */
  2105. case CK_Left:
  2106. case CK_Right:
  2107. case CK_Left_Highlight:
  2108. case CK_Right_Highlight:
  2109. edit->force |= REDRAW_CHAR_ONLY;
  2110. }
  2111. /* basic cursor key commands */
  2112. switch (command) {
  2113. case CK_BackSpace:
  2114. if (option_backspace_through_tabs && is_in_indent (edit)) {
  2115. while (edit_get_byte (edit, edit->curs1 - 1) != '\n'
  2116. && edit->curs1 > 0)
  2117. edit_backspace (edit);
  2118. break;
  2119. } else {
  2120. if (option_fake_half_tabs) {
  2121. int i;
  2122. if (is_in_indent (edit) && right_of_four_spaces (edit)) {
  2123. for (i = 0; i < HALF_TAB_SIZE; i++)
  2124. edit_backspace (edit);
  2125. break;
  2126. }
  2127. }
  2128. }
  2129. edit_backspace (edit);
  2130. break;
  2131. case CK_Delete:
  2132. if (option_fake_half_tabs) {
  2133. int i;
  2134. if (is_in_indent (edit) && left_of_four_spaces (edit)) {
  2135. for (i = 1; i <= HALF_TAB_SIZE; i++)
  2136. edit_delete (edit);
  2137. break;
  2138. }
  2139. }
  2140. edit_delete (edit);
  2141. break;
  2142. case CK_Delete_Word_Left:
  2143. edit_left_delete_word (edit);
  2144. break;
  2145. case CK_Delete_Word_Right:
  2146. edit_right_delete_word (edit);
  2147. break;
  2148. case CK_Delete_Line:
  2149. edit_delete_line (edit);
  2150. break;
  2151. case CK_Delete_To_Line_End:
  2152. edit_delete_to_line_end (edit);
  2153. break;
  2154. case CK_Delete_To_Line_Begin:
  2155. edit_delete_to_line_begin (edit);
  2156. break;
  2157. case CK_Enter:
  2158. if (option_auto_para_formatting) {
  2159. edit_double_newline (edit);
  2160. if (option_return_does_auto_indent)
  2161. edit_auto_indent (edit);
  2162. format_paragraph (edit, 0);
  2163. } else {
  2164. edit_insert (edit, '\n');
  2165. if (option_return_does_auto_indent) {
  2166. edit_auto_indent (edit);
  2167. }
  2168. }
  2169. break;
  2170. case CK_Return:
  2171. edit_insert (edit, '\n');
  2172. break;
  2173. case CK_Page_Up:
  2174. case CK_Page_Up_Highlight:
  2175. edit_move_up (edit, edit->num_widget_lines - 1, 1);
  2176. break;
  2177. case CK_Page_Down:
  2178. case CK_Page_Down_Highlight:
  2179. edit_move_down (edit, edit->num_widget_lines - 1, 1);
  2180. break;
  2181. case CK_Left:
  2182. case CK_Left_Highlight:
  2183. if (option_fake_half_tabs) {
  2184. if (is_in_indent (edit) && right_of_four_spaces (edit)) {
  2185. edit_cursor_move (edit, -HALF_TAB_SIZE);
  2186. edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
  2187. break;
  2188. }
  2189. }
  2190. edit_cursor_move (edit, -1);
  2191. break;
  2192. case CK_Right:
  2193. case CK_Right_Highlight:
  2194. if (option_fake_half_tabs) {
  2195. if (is_in_indent (edit) && left_of_four_spaces (edit)) {
  2196. edit_cursor_move (edit, HALF_TAB_SIZE);
  2197. edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
  2198. break;
  2199. }
  2200. }
  2201. edit_cursor_move (edit, 1);
  2202. break;
  2203. case CK_Begin_Page:
  2204. case CK_Begin_Page_Highlight:
  2205. edit_begin_page (edit);
  2206. break;
  2207. case CK_End_Page:
  2208. case CK_End_Page_Highlight:
  2209. edit_end_page (edit);
  2210. break;
  2211. case CK_Word_Left:
  2212. case CK_Word_Left_Highlight:
  2213. edit_left_word_move_cmd (edit);
  2214. break;
  2215. case CK_Word_Right:
  2216. case CK_Word_Right_Highlight:
  2217. edit_right_word_move_cmd (edit);
  2218. break;
  2219. case CK_Up:
  2220. case CK_Up_Highlight:
  2221. edit_move_up (edit, 1, 0);
  2222. break;
  2223. case CK_Down:
  2224. case CK_Down_Highlight:
  2225. edit_move_down (edit, 1, 0);
  2226. break;
  2227. case CK_Paragraph_Up:
  2228. case CK_Paragraph_Up_Highlight:
  2229. edit_move_up_paragraph (edit, 0);
  2230. break;
  2231. case CK_Paragraph_Down:
  2232. case CK_Paragraph_Down_Highlight:
  2233. edit_move_down_paragraph (edit, 0);
  2234. break;
  2235. case CK_Scroll_Up:
  2236. case CK_Scroll_Up_Highlight:
  2237. edit_move_up (edit, 1, 1);
  2238. break;
  2239. case CK_Scroll_Down:
  2240. case CK_Scroll_Down_Highlight:
  2241. edit_move_down (edit, 1, 1);
  2242. break;
  2243. case CK_Home:
  2244. case CK_Home_Highlight:
  2245. edit_cursor_to_bol (edit);
  2246. break;
  2247. case CK_End:
  2248. case CK_End_Highlight:
  2249. edit_cursor_to_eol (edit);
  2250. break;
  2251. case CK_Tab:
  2252. edit_tab_cmd (edit);
  2253. if (option_auto_para_formatting) {
  2254. format_paragraph (edit, 0);
  2255. edit->force |= REDRAW_PAGE;
  2256. } else
  2257. check_and_wrap_line (edit);
  2258. break;
  2259. case CK_Toggle_Insert:
  2260. edit->overwrite = (edit->overwrite == 0);
  2261. break;
  2262. case CK_Mark:
  2263. if (edit->mark2 >= 0) {
  2264. if (column_highlighting)
  2265. edit_push_action (edit, COLUMN_ON);
  2266. column_highlighting = 0;
  2267. }
  2268. edit_mark_cmd (edit, 0);
  2269. break;
  2270. case CK_Column_Mark:
  2271. if (!column_highlighting)
  2272. edit_push_action (edit, COLUMN_OFF);
  2273. column_highlighting = 1;
  2274. edit_mark_cmd (edit, 0);
  2275. break;
  2276. case CK_Unmark:
  2277. if (column_highlighting)
  2278. edit_push_action (edit, COLUMN_ON);
  2279. column_highlighting = 0;
  2280. edit_mark_cmd (edit, 1);
  2281. break;
  2282. case CK_Toggle_Bookmark:
  2283. book_mark_clear (edit, edit->curs_line, BOOK_MARK_FOUND_COLOR);
  2284. if (book_mark_query_color (edit, edit->curs_line, BOOK_MARK_COLOR))
  2285. book_mark_clear (edit, edit->curs_line, BOOK_MARK_COLOR);
  2286. else
  2287. book_mark_insert (edit, edit->curs_line, BOOK_MARK_COLOR);
  2288. break;
  2289. case CK_Flush_Bookmarks:
  2290. book_mark_flush (edit, BOOK_MARK_COLOR);
  2291. book_mark_flush (edit, BOOK_MARK_FOUND_COLOR);
  2292. edit->force |= REDRAW_PAGE;
  2293. break;
  2294. case CK_Next_Bookmark:
  2295. if (edit->book_mark) {
  2296. struct _book_mark *p;
  2297. p = (struct _book_mark *) book_mark_find (edit,
  2298. edit->curs_line);
  2299. if (p->next) {
  2300. p = p->next;
  2301. if (p->line >= edit->start_line + edit->num_widget_lines
  2302. || p->line < edit->start_line)
  2303. edit_move_display (edit,
  2304. p->line -
  2305. edit->num_widget_lines / 2);
  2306. edit_move_to_line (edit, p->line);
  2307. }
  2308. }
  2309. break;
  2310. case CK_Prev_Bookmark:
  2311. if (edit->book_mark) {
  2312. struct _book_mark *p;
  2313. p = (struct _book_mark *) book_mark_find (edit,
  2314. edit->curs_line);
  2315. while (p->line == edit->curs_line)
  2316. if (p->prev)
  2317. p = p->prev;
  2318. if (p->line >= 0) {
  2319. if (p->line >= edit->start_line + edit->num_widget_lines
  2320. || p->line < edit->start_line)
  2321. edit_move_display (edit,
  2322. p->line -
  2323. edit->num_widget_lines / 2);
  2324. edit_move_to_line (edit, p->line);
  2325. }
  2326. }
  2327. break;
  2328. case CK_Beginning_Of_Text:
  2329. case CK_Beginning_Of_Text_Highlight:
  2330. edit_move_to_top (edit);
  2331. break;
  2332. case CK_End_Of_Text:
  2333. case CK_End_Of_Text_Highlight:
  2334. edit_move_to_bottom (edit);
  2335. break;
  2336. case CK_Copy:
  2337. edit_block_copy_cmd (edit);
  2338. break;
  2339. case CK_Remove:
  2340. edit_block_delete_cmd (edit);
  2341. break;
  2342. case CK_Move:
  2343. edit_block_move_cmd (edit);
  2344. break;
  2345. case CK_XStore:
  2346. edit_copy_to_X_buf_cmd (edit);
  2347. break;
  2348. case CK_XCut:
  2349. edit_cut_to_X_buf_cmd (edit);
  2350. break;
  2351. case CK_XPaste:
  2352. edit_paste_from_X_buf_cmd (edit);
  2353. break;
  2354. case CK_Selection_History:
  2355. edit_paste_from_history (edit);
  2356. break;
  2357. case CK_Save_As:
  2358. edit_save_as_cmd (edit);
  2359. break;
  2360. case CK_Save:
  2361. edit_save_confirm_cmd (edit);
  2362. break;
  2363. case CK_Load:
  2364. edit_load_cmd (edit);
  2365. break;
  2366. case CK_Save_Block:
  2367. edit_save_block_cmd (edit);
  2368. break;
  2369. case CK_Insert_File:
  2370. edit_insert_file_cmd (edit);
  2371. break;
  2372. case CK_Toggle_Syntax:
  2373. if ((option_syntax_highlighting ^= 1) == 1)
  2374. edit_load_syntax (edit, NULL, option_syntax_type);
  2375. edit->force |= REDRAW_PAGE;
  2376. break;
  2377. case CK_Find:
  2378. edit_search_cmd (edit, 0);
  2379. break;
  2380. case CK_Find_Again:
  2381. edit_search_cmd (edit, 1);
  2382. break;
  2383. case CK_Replace:
  2384. edit_replace_cmd (edit, 0);
  2385. break;
  2386. case CK_Replace_Again:
  2387. edit_replace_cmd (edit, 1);
  2388. break;
  2389. case CK_Complete_Word:
  2390. edit_complete_word_cmd (edit);
  2391. break;
  2392. case CK_Exit:
  2393. dlg_stop (edit->widget.parent);
  2394. break;
  2395. case CK_New:
  2396. edit_new_cmd (edit);
  2397. break;
  2398. case CK_Help:
  2399. edit_help_cmd (edit);
  2400. break;
  2401. case CK_Refresh:
  2402. edit_refresh_cmd (edit);
  2403. break;
  2404. case CK_Date:{
  2405. char s[1024];
  2406. /* fool gcc to prevent a Y2K warning */
  2407. char time_format[] = "_c";
  2408. time_format[0] = '%';
  2409. FMT_LOCALTIME_CURRENT(s, sizeof(s), time_format);
  2410. edit_print_string (edit, s);
  2411. edit->force |= REDRAW_PAGE;
  2412. break;
  2413. }
  2414. case CK_Goto:
  2415. edit_goto_cmd (edit);
  2416. break;
  2417. case CK_Paragraph_Format:
  2418. format_paragraph (edit, 1);
  2419. edit->force |= REDRAW_PAGE;
  2420. break;
  2421. case CK_Delete_Macro:
  2422. edit_delete_macro_cmd (edit);
  2423. break;
  2424. case CK_Match_Bracket:
  2425. edit_goto_matching_bracket (edit);
  2426. break;
  2427. case CK_User_Menu:
  2428. user_menu (edit);
  2429. break;
  2430. case CK_Sort:
  2431. edit_sort_cmd (edit);
  2432. break;
  2433. case CK_ExtCmd:
  2434. edit_ext_cmd (edit);
  2435. break;
  2436. case CK_Mail:
  2437. edit_mail_dialog (edit);
  2438. break;
  2439. case CK_Shell:
  2440. view_other_cmd ();
  2441. break;
  2442. case CK_Select_Codepage:
  2443. edit_select_codepage_cmd (edit);
  2444. break;
  2445. case CK_Insert_Literal:
  2446. edit_insert_literal_cmd (edit);
  2447. break;
  2448. case CK_Execute_Macro:
  2449. edit_execute_macro_cmd (edit);
  2450. break;
  2451. case CK_Begin_End_Macro:
  2452. edit_begin_end_macro_cmd (edit);
  2453. break;
  2454. case CK_Ext_Mode:
  2455. edit->extmod = 1;
  2456. break;
  2457. default:
  2458. break;
  2459. }
  2460. /* CK_Pipe_Block */
  2461. if ((command / 1000) == 1) /* a shell command */
  2462. edit_block_process_cmd (edit, shell_cmd[command - 1000], 1);
  2463. if (command > CK_Macro (0) && command <= CK_Last_Macro) { /* a macro command */
  2464. struct macro m[MAX_MACRO_LENGTH];
  2465. int nm;
  2466. if (edit_load_macro_cmd (edit, m, &nm, command - 2000))
  2467. edit_execute_macro (edit, m, nm);
  2468. }
  2469. /* keys which must set the col position, and the search vars */
  2470. switch (command) {
  2471. case CK_Find:
  2472. case CK_Find_Again:
  2473. case CK_Replace:
  2474. case CK_Replace_Again:
  2475. case CK_Complete_Word:
  2476. edit->prev_col = edit_get_col (edit);
  2477. break;
  2478. case CK_Up:
  2479. case CK_Up_Highlight:
  2480. case CK_Down:
  2481. case CK_Down_Highlight:
  2482. case CK_Page_Up:
  2483. case CK_Page_Up_Highlight:
  2484. case CK_Page_Down:
  2485. case CK_Page_Down_Highlight:
  2486. case CK_Beginning_Of_Text:
  2487. case CK_Beginning_Of_Text_Highlight:
  2488. case CK_End_Of_Text:
  2489. case CK_End_Of_Text_Highlight:
  2490. case CK_Paragraph_Up:
  2491. case CK_Paragraph_Up_Highlight:
  2492. case CK_Paragraph_Down:
  2493. case CK_Paragraph_Down_Highlight:
  2494. case CK_Scroll_Up:
  2495. case CK_Scroll_Up_Highlight:
  2496. case CK_Scroll_Down:
  2497. case CK_Scroll_Down_Highlight:
  2498. edit->search_start = edit->curs1;
  2499. edit->found_len = 0;
  2500. break;
  2501. default:
  2502. edit->found_len = 0;
  2503. edit->prev_col = edit_get_col (edit);
  2504. edit->search_start = edit->curs1;
  2505. }
  2506. edit_find_bracket (edit);
  2507. if (option_auto_para_formatting) {
  2508. switch (command) {
  2509. case CK_BackSpace:
  2510. case CK_Delete:
  2511. case CK_Delete_Word_Left:
  2512. case CK_Delete_Word_Right:
  2513. case CK_Delete_To_Line_End:
  2514. case CK_Delete_To_Line_Begin:
  2515. format_paragraph (edit, 0);
  2516. edit->force |= REDRAW_PAGE;
  2517. }
  2518. }
  2519. }
  2520. static void
  2521. edit_execute_macro (WEdit *edit, struct macro macro[], int n)
  2522. {
  2523. int i = 0;
  2524. if (edit->macro_depth++ > 256) {
  2525. edit_error_dialog (_("Error"), _("Macro recursion is too deep"));
  2526. edit->macro_depth--;
  2527. return;
  2528. }
  2529. edit->force |= REDRAW_PAGE;
  2530. for (; i < n; i++) {
  2531. edit_execute_cmd (edit, macro[i].command, macro[i].ch);
  2532. }
  2533. edit_update_screen (edit);
  2534. edit->macro_depth--;
  2535. }
  2536. /* User edit menu, like user menu (F2) but only in editor. */
  2537. static void
  2538. user_menu (WEdit * edit)
  2539. {
  2540. FILE *fd;
  2541. int nomark;
  2542. struct stat status;
  2543. long start_mark, end_mark;
  2544. char *block_file = concat_dir_and_file (home_dir, BLOCK_FILE);
  2545. int rc = 0;
  2546. nomark = eval_marks (edit, &start_mark, &end_mark);
  2547. if (!nomark) /* remember marked or not */
  2548. edit_save_block (edit, block_file, start_mark, end_mark);
  2549. /* run shell scripts from menu */
  2550. user_menu_cmd (edit);
  2551. if (mc_stat (block_file, &status) != 0 || !status.st_size) {
  2552. /* no block messages */
  2553. goto cleanup;
  2554. }
  2555. if (!nomark) {
  2556. /* i.e. we have marked block */
  2557. rc = edit_block_delete_cmd (edit);
  2558. }
  2559. if (!rc) {
  2560. edit_insert_file (edit, block_file);
  2561. }
  2562. /* truncate block file */
  2563. if ((fd = fopen (block_file, "w"))) {
  2564. fclose (fd);
  2565. }
  2566. edit_refresh_cmd (edit);
  2567. edit->force |= REDRAW_COMPLETELY;
  2568. cleanup:
  2569. g_free (block_file);
  2570. }