1 /* -*- mode: C; mode: fold; -*- */ 2 /* Copyright (c) 1992, 1998 John E. Davis 3 * This file is part of JED editor library source. 4 * 5 * You may distribute this file under the terms the GNU General Public 6 * License. See the file COPYING for more information. 7 */ 8 #include "config.h" 9 #include "jed-feat.h" 10 11 #include <stdio.h> 12 #include "buffer.h" 13 #include "undo.h" 14 #include "ins.h" 15 #include "line.h" 16 #include "misc.h" 17 #include "kanji.h" 18 19 20 #define LAST_UNDO CBuf->undo->Last_Undo 21 #define FIRST_UNDO CBuf->undo->First_Undo 22 #define UNDO_RING CBuf->undo->Undo_Ring 23 24 #ifdef UNDO_HAS_REDO 25 # define CURRENT_UNDO CBuf->undo->Current_Undo 26 #endif 27 28 static int Undo_In_Progress = 0; 29 int Undo_Buf_Unch_Flag; /* 1 if buffer prev not modified */ 30 31 #ifdef UNDO_HAS_REDO 32 #define DONT_RECORD_UNDO (!(CBuf->flags & UNDO_ENABLED)\ 33 || (CBuf->undo == NULL)) 34 #else 35 #define DONT_RECORD_UNDO (!(CBuf->flags & UNDO_ENABLED)\ 36 || (CBuf->undo == NULL) || Undo_In_Progress) 37 #endif 38 39 #define UNDO_BD_FLAG 0x8000 40 #define UNDO_UNCHANGED_FLAG 0x4000 41 42 #ifdef UNDO_HAS_REDO 43 # define IS_UNDO_BD (CURRENT_UNDO->type & UNDO_BD_FLAG) 44 #else 45 # define IS_UNDO_BD (LAST_UNDO->type & UNDO_BD_FLAG) 46 #endif 47 prepare_next_undo(void)48static void prepare_next_undo(void) /*{{{*/ 49 { 50 LAST_UNDO++; 51 if (LAST_UNDO >= UNDO_RING + MAX_UNDOS) LAST_UNDO = UNDO_RING; 52 if (LAST_UNDO == FIRST_UNDO) 53 { 54 FIRST_UNDO++; 55 #ifdef UNDO_HAS_REDO 56 if (FIRST_UNDO >= UNDO_RING + MAX_UNDOS) FIRST_UNDO = UNDO_RING; 57 #endif 58 } 59 #ifdef UNDO_HAS_REDO 60 if (LAST_UNDO == CURRENT_UNDO) /* undo-ring overflow will trash */ 61 CURRENT_UNDO = NULL; /* further undos */ 62 #else 63 if (FIRST_UNDO >= UNDO_RING + MAX_UNDOS) FIRST_UNDO = UNDO_RING; 64 #endif 65 66 67 LAST_UNDO->type = 0; 68 LAST_UNDO->misc = 0; 69 } 70 71 /*}}}*/ 72 73 #ifdef UNDO_HAS_REDO 74 /* Returns True if there is still undo info to be processed. */ 75 #define MORE_UNDO_INFO (CURRENT_UNDO && (CURRENT_UNDO->type)) 76 #endif 77 record_deletion(unsigned char * p,int n)78void record_deletion (unsigned char *p, int n) /*{{{*/ 79 { 80 int misc; 81 unsigned char *pb; 82 83 if (DONT_RECORD_UNDO || (n == 0)) return; 84 85 while (1) 86 { 87 if (((LAST_UNDO->type & 0xFF) == 0) 88 || ((LAST_UNDO->type & CDELETE) 89 && (LAST_UNDO->linenum == LineNum + CBuf->nup) 90 && (LAST_UNDO->point == Point))) 91 { 92 if (LAST_UNDO->type != 0) misc = LAST_UNDO->misc; else misc = 0; 93 pb = LAST_UNDO->buf + misc; 94 while (((misc < 8) && n && !iskanji(*p)) || ((misc < 7) && (1 < n) && iskanji(*p))) 95 { 96 if(iskanji(*p)) 97 { 98 *pb++ = *p++; 99 misc++; 100 n--; 101 } 102 *pb++ = *p++; 103 misc++; 104 n--; 105 } 106 LAST_UNDO->misc = misc; 107 LAST_UNDO->type |= CDELETE; 108 LAST_UNDO->linenum = LineNum + CBuf->nup; 109 LAST_UNDO->point = Point; 110 if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; 111 Undo_Buf_Unch_Flag = 0; 112 } 113 114 if (n == 0) 115 break; 116 117 prepare_next_undo(); 118 } 119 120 if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; 121 #ifdef UNDO_HAS_REDO 122 set_current_undo (); 123 #endif 124 } 125 126 /*}}}*/ 127 undo(void)128int undo (void) /*{{{*/ 129 { 130 int line; 131 CHECK_READ_ONLY 132 if (!(CBuf->flags & UNDO_ENABLED)) 133 { 134 msg_error("Undo not enabled for this buffer."); 135 return(0); 136 } 137 else if ((CBuf->undo == NULL) 138 #ifdef UNDO_HAS_REDO 139 || (0 == MORE_UNDO_INFO) 140 #else 141 || (LAST_UNDO->type == 0) 142 #endif 143 ) 144 { 145 msg_error("No more undo information."); 146 return(0); 147 } 148 Undo_In_Progress = 1; 149 150 do 151 { 152 #ifdef UNDO_HAS_REDO 153 line = (int) CURRENT_UNDO->linenum; 154 #else 155 line = (int) LAST_UNDO->linenum; 156 #endif 157 if ((line <= (int) CBuf->nup) || ((unsigned int) line > CBuf->nup + Max_LineNum)) 158 { 159 msg_error("Next undo lies outside visible buffer."); 160 break; 161 } 162 line -= CBuf->nup; 163 goto_line(&line); 164 #ifdef UNDO_HAS_REDO 165 Point = CURRENT_UNDO->point; 166 #else 167 Point = LAST_UNDO->point; 168 #endif 169 170 #ifdef UNDO_HAS_REDO 171 switch (CURRENT_UNDO->type & 0xFF) 172 #else 173 switch (LAST_UNDO->type & 0xFF) 174 #endif 175 { 176 #ifdef UNDO_HAS_REDO 177 case CDELETE: ins_chars(CURRENT_UNDO->buf, CURRENT_UNDO->misc); 178 /* Point = CURRENT_UNDO->point; */ 179 #else 180 case CDELETE: ins_chars(LAST_UNDO->buf, LAST_UNDO->misc); 181 /* Point = LAST_UNDO->point; */ 182 #endif 183 break; 184 185 #ifdef UNDO_HAS_REDO 186 case CINSERT: deln(&CURRENT_UNDO->misc); 187 #else 188 case CINSERT: deln(&LAST_UNDO->misc); 189 #endif 190 break; 191 192 case NLINSERT: del(); break; 193 194 default: return(1); 195 } 196 197 #ifdef UNDO_HAS_REDO 198 if (CURRENT_UNDO == NULL) break; 199 /* no more undo info after overflow */ 200 201 /* above calls to ins_chars/deln/del may overflow the undo-ring */ 202 if (CURRENT_UNDO->type & UNDO_UNCHANGED_FLAG) 203 { 204 mark_buffer_modified (0); 205 } 206 207 if (CURRENT_UNDO == FIRST_UNDO) 208 { 209 CURRENT_UNDO = NULL ; 210 break ; /* no more undo info */ 211 } 212 213 CURRENT_UNDO--; 214 if (CURRENT_UNDO < UNDO_RING) CURRENT_UNDO = UNDO_RING + MAX_UNDOS - 1; 215 #else 216 if (LAST_UNDO->type & UNDO_UNCHANGED_FLAG) 217 { 218 mark_buffer_modified (0); 219 } 220 221 if (LAST_UNDO == FIRST_UNDO) LAST_UNDO->type = 0; 222 else 223 { 224 LAST_UNDO--; 225 if (LAST_UNDO < UNDO_RING) LAST_UNDO = UNDO_RING + MAX_UNDOS - 1; 226 } 227 #endif 228 } 229 #ifdef UNDO_HAS_REDO 230 while ((!IS_UNDO_BD) && (CURRENT_UNDO->type)); 231 #else 232 while ((!IS_UNDO_BD) && (LAST_UNDO->type)); 233 #endif 234 235 message("Undo!"); 236 Undo_In_Progress = 0; 237 return(1); 238 } 239 240 /*}}}*/ 241 record_insertion(int n)242void record_insertion(int n) /*{{{*/ 243 { 244 if (DONT_RECORD_UNDO || !n) return; 245 246 if ((Undo_Buf_Unch_Flag) && (LAST_UNDO->type)) 247 { 248 prepare_next_undo (); 249 } 250 251 if (LAST_UNDO->type == 0) 252 { 253 LAST_UNDO->misc = n; 254 LAST_UNDO->point = Point; 255 } 256 else if ((LAST_UNDO->type & CINSERT) && (LAST_UNDO->linenum == LineNum + CBuf->nup) 257 && (LAST_UNDO->point + LAST_UNDO->misc == Point) 258 && !(LAST_UNDO->misc == 32 && n == 1 && iskanji(CLine->data[Point]) && !iskanji2nd(CLine->data, Point))) 259 { 260 LAST_UNDO->misc += n; 261 } 262 else 263 { 264 prepare_next_undo(); 265 LAST_UNDO->point = Point; 266 LAST_UNDO->misc = n; 267 } 268 269 LAST_UNDO->type |= CINSERT; 270 if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; 271 LAST_UNDO->linenum = LineNum + CBuf->nup; 272 #ifdef UNDO_HAS_REDO 273 set_current_undo (); 274 #endif 275 } 276 277 /*}}}*/ 278 record_newline_insertion()279void record_newline_insertion() /*{{{*/ 280 { 281 if (DONT_RECORD_UNDO) return; 282 if (LAST_UNDO->type != 0) prepare_next_undo(); 283 if (Undo_Buf_Unch_Flag) LAST_UNDO->type |= UNDO_UNCHANGED_FLAG; 284 LAST_UNDO->point = Point; 285 LAST_UNDO->misc = 0; 286 LAST_UNDO->type |= NLINSERT; 287 LAST_UNDO->linenum = LineNum + CBuf->nup; 288 #ifdef UNDO_HAS_REDO 289 set_current_undo (); 290 #endif 291 } 292 293 /*}}}*/ 294 delete_undo_ring(Buffer * b)295void delete_undo_ring(Buffer *b) /*{{{*/ 296 { 297 SLfree ((char *)b->undo); 298 } 299 300 /*}}}*/ 301 create_undo_ring()302void create_undo_ring() /*{{{*/ 303 { 304 Undo_Type *ur; 305 Undo_Object_Type *uo; 306 int n; 307 308 if (NULL == (ur = (Undo_Type *) SLmalloc (sizeof(Undo_Type)))) 309 { 310 msg_error("Unable to malloc space for undo!"); 311 return; 312 } 313 CBuf->undo = ur; 314 uo = ur->Undo_Ring; 315 ur->Last_Undo = ur->First_Undo = uo; 316 #ifdef UNDO_HAS_REDO 317 ur->Current_Undo = NULL; 318 #endif 319 320 n = MAX_UNDOS; 321 while (n--) 322 { 323 uo->type = 0; 324 uo++; 325 } 326 } 327 328 /*}}}*/ 329 mark_undo_boundary(Buffer * b)330void mark_undo_boundary (Buffer *b) /*{{{*/ 331 { 332 Buffer *s = CBuf; 333 334 CBuf = b; 335 336 if (!DONT_RECORD_UNDO && (LAST_UNDO->type != 0)) 337 { 338 LAST_UNDO->type |= UNDO_BD_FLAG; 339 } 340 CBuf = s; 341 } 342 343 /*}}}*/ 344 unmark_undo_boundary(Buffer * b)345void unmark_undo_boundary (Buffer *b) /*{{{*/ 346 { 347 #if 1 348 (void) b; 349 #else 350 Buffer *s = CBuf; 351 352 CBuf = b; 353 354 if (!DONT_RECORD_UNDO && (LAST_UNDO->type != 0)) 355 { 356 LAST_UNDO->type &= ~UNDO_BD_FLAG; 357 } 358 CBuf = s; 359 #endif 360 } 361 362 /*}}}*/ 363 364 #ifdef UNDO_HAS_REDO set_current_undo()365void set_current_undo() /* Called when text is inserted, deleted, */ /*{{{*/ 366 { /* or the abort key is pressed. */ 367 if ((!Undo_In_Progress) && CBuf->undo) 368 { 369 CURRENT_UNDO = LAST_UNDO ; 370 } 371 } 372 373 /*}}}*/ 374 update_undo_unchanged(void)375void update_undo_unchanged (void) /*{{{*/ 376 /* Update unchange flags after a buffer save. The reason for this is 377 * that after a save, undoing on the buffer does not affect the disk file. 378 */ 379 { 380 Undo_Object_Type *uo; 381 int n; 382 383 if (DONT_RECORD_UNDO) return; 384 385 uo = UNDO_RING ; 386 n = MAX_UNDOS; 387 while (n--) 388 { 389 uo->type &= ~UNDO_UNCHANGED_FLAG; 390 uo++; 391 } 392 393 CURRENT_UNDO = LAST_UNDO ; 394 } 395 396 /*}}}*/ 397 #endif 398 399 400