1 {
2 Descripción
3 ===========
4 Utilidades para la creación de editores con el resaltador SynFacilSyn.
5
6 Trabaja con SynFacilCompletion 1.0 o superior
7 }
8 unit SynFacilUtils; {$mode objfpc}{$H+}
9 interface
10 uses Classes, SysUtils, Clipbrd, SynEdit, SynEditMarkupHighAll,
11 lconvencoding, Graphics, FileUtil, Dialogs, Controls, Forms, LCLType, ComCtrls,
12 SynEditKeyCmds, SynEditTypes, Menus, strUtils, LazUTF8, MisUtils, FormSelFuente,
13 SynFacilCompletion; //necesario para rutinas de manejo de sintaxis
14
15 type
16 //Tipos de delimitador de línea de archivo.
17 TLineEnd = (TAR_DESC, //Tipo desconocido
18 TAR_DOS, //Tipo Windows/DOS
19 TAR_UNIX, //Tipo Unix/Linux
20 TAR_MAC //Tipo Mac OS
21 );
22
23 { TSynFacilEditor }
24 TEventoArchivo = procedure of object;
25
26 //Define las propiedades que debe tener un texto que se está editando
27 TSynFacilEditor = class
28 procedure edKeyPress(Sender: TObject; var Key: char);
29 procedure edUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
30 private
31 procedure DoSelectLanguage(Sender: TObject);
32 procedure CheckLanguageMenu(XMLfile: string);
33 procedure ReplaceDialog1Find(Sender: TObject);
34 procedure ReplaceDialog1Replace(Sender: TObject);
35 protected
36 ed : TSynEdit; //referencia al editor
37 fPanLangName: TStatusPanel;
38 mnRecents : TMenuItem; //Menú de archivos recientes
39 mnLanguages : TMenuItem; //Menú de lenguajes
40 mnLineEnding: TMenuItem; //Menú de Fin de línea
41 mnEncoding : TMenuItem; //Menú de Codificación de texto
42 LangPath : string; //ruta donde están los lengaujes
43 MaxRecents : integer; //Máxima cantidad de archivos recientes
44 //paneles con información del estado del editor
45 fPanFileSaved : TStatusPanel; //Panel para mensaje "Guardado"
46 fPanCursorPos : TStatusPanel; //Panel para mostrar posición del cursor
47 //paneles para información del archivo
48 fPanFileName : TStatusPanel; //Panel para mostrar el nombre de archivo
49 fPanForEndLin : TStatusPanel; //Panel para mostrar el tipo de delimitador de línea
50 fPanCodifFile : TStatusPanel; //Panel para mostrar la codificaión de archivo
51 procedure edChange(Sender: TObject);
52 procedure edStatusChange(Sender: TObject; Changes: TSynStatusChanges);
53 procedure edMouseDown(Sender: TObject; Button: TMouseButton;
54 Shift: TShiftState; X, Y: Integer);
55 procedure edKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
56 procedure edKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
57 procedure edCommandProcessed(Sender: TObject;
58 var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
59
60 //Estado de modificación
61 procedure SetModified(valor: boolean);
GetModifiednull62 function GetModified: boolean;
63 procedure SetPanCodifFile(AValue: TStatusPanel);
64 procedure SetPanCursorPos(AValue: TStatusPanel);
65 procedure SetPanFileName(AValue: TStatusPanel);
66 procedure SetPanFileSaved(AValue: TStatusPanel);
67 procedure SetPanForEndLin(AValue: TStatusPanel);
68 procedure SetPanLangName(AValue: TStatusPanel);
GetTextnull69 function GetText: string;
70 procedure SetText(AValue: string);
71 public
72 FileName: string; //Nombre del archivo
73 DelArc : TLineEnd; //Tipo de delimitador de fin de línea
74 CodArc : string; //codificación de archivo
75 linErr : integer; //línea de error. SOlo usada para marcar un error
76 Error : string; //mensaje de error en alguna operación
77 extDef : string; //extensión por defecto para los archivos (txt, xml, ...)
78 nomDef : string; //nombre por defecto pàra nuevos archivos
79 RecentFiles: TStringList; //Lista de archivos recientes
80 hl : TSynFacilComplet; //Resaltador.
81 //eventos
82 OnChangeEditorState:TEventoArchivo; {Cuando cambia el estado de modificado, con opción
83 "Undo", con "Redo", con opción "Copiar", "Cortar", "Pegar"}
84 OnChangeFileInform: TEventoArchivo; {Cuando cambia información de nombre de archivo, tipo
85 de delimitador de línea o tipo de codificación}
86 OnSelectionChange : TEventoArchivo; //Cuando cambia el área seleccionada
87 OnFileOpened : TEventoArchivo; //Cuando se ha cargado un nuevo archivo
88 //Reflejo de los eventos de TSynEdit:
89 OnEditChange : TNotifyEvent;
90 OnMouseDown : TMouseEvent;
91 OnKeyUp : TKeyEvent;
92 OnKeyDown : TKeyEvent;
93 OnKeyPress : TKeyPressEvent;
94 OnUTF8KeyPress: TUTF8KeyPressEvent;
95 //funciones comunes de un editor
96 procedure NewFile(QuerySave: boolean=true); virtual;
97 procedure LoadFile(arc8: string); virtual;
98 procedure SaveFile; virtual;
OpenDialognull99 function OpenDialog(OpenDialog1: TOpenDialog): boolean; virtual;
SaveAsDialognull100 function SaveAsDialog(SaveDialog1: TSaveDialog): boolean; virtual;
SaveQuerynull101 function SaveQuery: boolean; virtual;
102 //búsqueda/reemplazo
103 procedure FindDialog;
104 procedure FindNextWord(Sender: TObject); //el método FindNext() ya existe
105 procedure ReplaceDialog;
106 //herramientas
107 procedure TabToSpaces(fSelFuente: TfrmSelFuente);
108 procedure TrimLines(fSelFuente: TfrmSelFuente);
FiltLinesnull109 function FiltLines(fSelFuente: TfrmSelFuente; sal: TStringList): boolean;
110 //Funciones para cambio de Fin de Línea y Codificación
111 procedure ChangeEndLineDelim(nueFor: TLineEnd); //cambia Fin de línea
112 procedure InitMenuLineEnding(mnLineEnding0: TMenuItem); //configura menú
113 procedure LineEndingClick(Sender: TObject); //evento click
114 procedure ChangeEncoding(nueCod: string); //cambia codificación
115 procedure InitMenuEncoding(mnEncoding0: TMenuItem); //configura menú
116 procedure EncodingClick(Sender: TObject); //evento click
117 procedure ChangeFileInform;
118 //funciones para completado de código
119 procedure CloseCompletionWindow;
120 public //Espejo de funciones comunes del editor
121 procedure Cut;
122 procedure Copy;
123 procedure Paste;
124 procedure Undo;
125 procedure Redo;
126 procedure SelectAll;
127 //Lee estado
CanUndonull128 function CanUndo: boolean;
CanRedonull129 function CanRedo: boolean;
CanCopynull130 function CanCopy: boolean;
CanPastenull131 function CanPaste: boolean;
132
133 property Modified: boolean read GetModified write SetModified;
134 public //Paneles informativos
135 property PanFileSaved: TStatusPanel read fPanFileSaved write SetPanFileSaved;
136 property PanCursorPos: TStatusPanel read fPanCursorPos write SetPanCursorPos;
137
138 property PanFileName : TStatusPanel read fPanFileName write SetPanFileName;
139 property PanForEndLin: TStatusPanel read fPanForEndLin write SetPanForEndLin;
140 property PanCodifFile: TStatusPanel read fPanCodifFile write SetPanCodifFile;
141 property PanLangName : TStatusPanel read fPanLangName write SetPanLangName;
142
143 property Text: string read GetText write SetText; //devuelve el contenido real del editor
144 procedure RefreshPanCursor; //Refresca panel de la posición del cursor
145 public //Rutinas de inicio
146 procedure InitMenuRecents(menRecents0: TMenuItem; RecentList: TStringList;
147 MaxRecents0: integer=5);
148 procedure RecentClick(Sender: TObject);
149 procedure ActualMenusReciente(Sender: TObject);
150 procedure AgregArcReciente(arch: string);
151
152 procedure InitMenuLanguages(menLanguage0: TMenuItem; LangPath0: string);
153 procedure LoadSyntaxFromFile(XMLfile: string); //carga un archivo de sintaxis
154 procedure LoadSyntaxFromPath(arc: string=''); //carga sintaxis viendo extensión de archivo
155 procedure SetLanguage(lang: string);
156 constructor Create(ed0: TsynEdit; nomDef0, extDef0: string); virtual;
157 destructor Destroy; override;
158 end;
159
160 procedure InicEditorC1(ed: TSynEdit);
161 procedure StringToFile(const s: string; const FileName: string);
StringFromFilenull162 function StringFromFile(const FileName: string): string;
163 procedure VerTipoArchivo(archivo: string; var Formato: TLineEnd; var Codificacion: string);
CargarArchivoLinnull164 function CargarArchivoLin(arc8: string; Lineas: TStrings;
165 var TipArc: TLineEnd; var CodArc: string): string;
GuardarArchivoLinnull166 function GuardarArchivoLin(arc0: string; Lineas: TStrings;
167 var TipArc: TLineEnd; var CodArc: string): string;
168 implementation
169 const
170 szChar = SizeOf(Char);
171
172 var
173 //Diálogos para búsqueda/reemplazo
174 FindDialog1: TFindDialog;
175 ReplaceDialog1: TReplaceDialog;
176
177 procedure msgErr(msje: string); //Rutina útil
178 //Mensaje de error
179 begin
180 Application.MessageBox(PChar(msje), '', MB_ICONERROR);
181 end;
182 procedure InicEditorC1(ed: TSynEdit);
183 //Inicia un editor con una configuración especial para empezar a trabajar con el.
184 var
185 SynMarkup: TSynEditMarkupHighlightAllCaret; //para resaltar palabras iguales
186 begin
187 //Inicia resaltado de palabras iguales
188 SynMarkup := TSynEditMarkupHighlightAllCaret(ed.MarkupByClass[TSynEditMarkupHighlightAllCaret]);
189 SynMarkup.MarkupInfo.FrameColor := clSilver;
190 SynMarkup.MarkupInfo.Background := TColor($FFF0B0);
191
192 SynMarkup.WaitTime := 250; // millisec
193 SynMarkup.Trim := True; // no spaces, if using selection
194 SynMarkup.FullWord := True; // only full words If "Foo" is under caret, do not mark it in "FooBar"
195 SynMarkup.IgnoreKeywords := true;
196
197 // ed.Font.Name:='Courier New';
198 // ed.Font.Size:=10;
199 ed.Options:=[eoHideRightMargin,eoBracketHighlight]; //quita la línea vertical
200 ed.Options := ed.Options + [eoKeepCaretX]; //Limita posición X del cursor para que no escape de la línea
201 ed.Options := ed.Options + [eoTabIndent]; //permite indentar con <Tab>
202 ed.Options2 := ed.Options2 + [eoCaretSkipTab]; //trata a las tabulaciones como un caracter
203 end;
204 procedure StringToFile(const s: string; const FileName: string);
205 /// saves a string to a file
206 var
207 FileStream: TFileStream;
208 begin
209 FileStream := TFileStream.Create(FileName, fmCreate);
210 try
211 FileStream.WriteBuffer(Pointer(s)^, (Length(s) * szChar));
212 finally
213 FreeAndNil(FileStream);
214 end; // try
215 end;
StringFromFilenull216 function StringFromFile(const FileName: string): string;
217 /// returns the content of the file as a string
218 var
219 FileStream: TFileStream;
220 begin
221 FileStream := TFileStream.Create(FileName, fmOpenRead);
222 try
223 SetLength(Result, (FileStream.Size div szChar));
224 FileStream.ReadBuffer(Pointer(Result)^, FileStream.Size);
225 finally
226 FreeAndNil(FileStream);
227 end; // try
228 end;
229 procedure VerTipoArchivo(archivo: string; var Formato: TLineEnd; var Codificacion: string);
230 (*Obtiene el tipo de delimitador de línea (Line Ending) de un archivo de texto, explorando
231 los primeros bytes de archivo. Solo explora los primeros 8K del archivo.
232 Si no encuentra un salto de línea en ese tamaño, no podrá deetrminar de que tipo de
233 archivo se trata. También explora el posible tipo de codificación usado.
234 *)
235 const TAM_BOL = 8192;
236 var ar: file;
237 bolsa : Array[0..TAM_BOL] of char; //deja un byte más para el delimitador
238 Pbolsa: PChar; //variable Pchar para "bolsa"
239 Pos13: Word; //posición de caracter #13
240 Pos10: Word; //posición de caracter #10
241 Leidos: Word; //bytes leidos
242 begin
243 //Lee bloque de datos
244 AssignFile(ar,archivo);
245 reset(ar,1); { TODO : Dio error al abrir un archivo de solo lectura }
246 BlockRead(ar, bolsa{%H-}, TAM_BOL, Leidos{%H-}); //Lectura masiva
247 CloseFile(ar);
248 bolsa[Leidos] := #0; //agrega delimitador
249 Pbolsa := @bolsa; //cadena PChar
250 //Explora en busca de delimitadores de línea
251 Pos13 := Pos(#13, Pbolsa);
252 Pos10 := Pos(#10, Pbolsa);
253 if Pos13 = 0 then
254 //solo hay separador #10 o ninguno
255 if Pos10<>0 then
256 Formato := TAR_UNIX //solo hay #10
257 else
258 Formato := TAR_DESC //no se encontró separador
259 else if Pos10 = 0 then
260 //solo hay separador #13 o ninguno
261 if Pos13 <> 0 then
262 Formato := TAR_MAC //solo hay #13
263 else
264 Formato := TAR_DESC //no se encontró separador
265 else if Pos10 = Pos13 + 1 then
266 Formato := TAR_DOS //no se encontró #13#10
267 else
268 Formato := TAR_DESC; //no se reconoce delimitadores
269 //Analiza codifiación
270 Codificacion := GuessEncoding(Pbolsa); //analiza los primeros bytes
271 { TODO : Ver por qué no detectó correctaente la carga de un archivo UTF-8 sin BOM }
272 end;
LineEnd_To_Strnull273 function LineEnd_To_Str(delim: TLineEnd): string;
274 //proporciona una descripción al tipo de delimitador
275 begin
276 Result := 'Unknown'; //'Desconoc.';
277 case delim of
278 TAR_DOS : Result := 'DOS/Win'; //DOS/Windows
279 TAR_UNIX: Result := 'UNIX/Linux';
280 TAR_MAC : Result := 'MAC OS';
281 TAR_DESC: Result := '<Unknown>'; //'Desconoc.';
282 end;
283 end;
Str_To_LineEndnull284 function Str_To_LineEnd(str: string): TLineEnd;
285 //proporciona una descripción al tipo de delimitador
286 begin
287 Result := TAR_DESC; //desconocido
288 case str of
289 'DOS/Win' : Result := TAR_DOS;
290 'UNIX/Linux': Result := TAR_UNIX;
291 'MAC OS' : Result := TAR_MAC;
292 'Unknown' : Result := TAR_DESC;
293 end;
294 end;
CargarArchivoLinnull295 function CargarArchivoLin(arc8: string; Lineas: TStrings;
296 var TipArc: TLineEnd; var CodArc: string): string;
297 {Carga el contenido de un archivo en un "TStrings". Si la codificación es diferente de
298 UTF-8, hace la conversión. Esta pensado para usarse en un SynEdit.
299 Además actualiza el Tipo de Delimitador de línea y la Codificación.
300 Devuelve una cadena que indica si hubo conversión }
301 var
302 arc0: String;
303 begin
304 CodArc := '';
305 arc0 := UTF8ToSys(arc8); //pone en modo ANSI
306 VerTipoArchivo(arc0, TipArc, CodArc); //actualiza tipo de archivo de trabajo
307 //Carga archivo solicitado
308 Lineas.LoadFromFile(arc8);
309 //realiza las conversiones necesarias, ya que "ed", solo maneja UTF-8
310 if CodArc = 'cp1252' then begin
311 Lineas.Text := CP1252ToUTF8(Lineas.Text);
312 Result := 'Convertido a UTF-8';
313 end else if CodArc = 'utf8bom' then begin
314 Lineas.Text := UTF8BOMToUTF8(Lineas.Text);
315 Result := 'Convertido a UTF-8';
316 end else if CodArc = 'ISO-8859-1' then begin
317 Lineas.Text := ISO_8859_1ToUTF8(Lineas.Text);
318 Result := 'Convertido a UTF-8';
319 end else if CodArc = 'utf8' then begin
320 Result := 'Sin convertir'; //no se cambia
321 end else begin //cualquier otra codificación se asume UTF-8 y no se cambia
322 //En windows tal vez debería cargarse cp1252 por defecto.
323 Result := 'utf8';
324 end;
325 end;
GuardarArchivoLinnull326 function GuardarArchivoLin(arc0: string; Lineas: TStrings;
327 var TipArc: TLineEnd; var CodArc: string): string;
328 {Guarda el contenido de un "TStrings" en un archivo. Si la codificación es diferente de
329 UTF-8, hace la conversión. Esta pensado para usarse en un SynEdit.
330 Además usa el Tipo de Delimitador de línea para guardar el archivo.
331 Devuelve una cadena con un mensaje de error, si es que lo hubiera. }
332 begin
333 Result := ''; //sin error por defecto
334 //configura tipo de separador
335 // case TipArc of
336 // TAR_DOS: TSynEditLines(ed.Lines).FileWriteLineEndType := sfleCrLf;
337 // TAR_UNIX: TSynEditLines(ed.Lines).FileWriteLineEndType := sfleLf;
338 // TAR_MAC: TSynEditLines(ed.Lines).FileWriteLineEndType := sfleCr;
339 // TAR_DESCON: TSynEditLines(ed.Lines).FileWriteLineEndType := sfleCrLf;
340 // end;
341 case TipArc of
342 TAR_DOS: Lineas.TextLineBreakStyle := tlbsCRLF;
343 TAR_UNIX: Lineas.TextLineBreakStyle := tlbsLF;
344 TAR_MAC: Lineas.TextLineBreakStyle := tlbsCR;
345 TAR_DESC: Lineas.TextLineBreakStyle := tlbsCRLF;
346 end;
347
348 if CodArc = 'utf8' then begin
349 //opción sin conversión
350 StringToFile(Lineas.Text,arc0);
351 end else if CodArc = 'cp1252' then begin
352 StringToFile(UTF8ToCP1252(Lineas.Text),arc0);
353 end else if CodArc = 'utf8bom' then begin
354 StringToFile(UTF8ToUTF8BOM(Lineas.Text),arc0);
355 end else if CodArc = 'ISO-8859-1' then begin
356 StringToFile(UTF8ToISO_8859_1(Lineas.Text),arc0);
357 end else begin //si es otra codificación, se guarda como UTF-8
358 MsgExc('¡Codificación de archivo desconocida!');
359 StringToFile(Lineas.Text,arc0);
360 end;
361 end;
362 { TSynFacilEditor }
363 //respuesta a eventos del editor
364 procedure TSynFacilEditor.edMouseDown(Sender: TObject; Button: TMouseButton;
365 Shift: TShiftState; X, Y: Integer);
366 begin
367 RefreshPanCursor;
368 linErr := 0; //para que quite la marca de fondo del error.
369 //Solo se notará cuando se refresque la línea en el editor.
370 //pasa el evento
371 if OnMouseDown <> nil then OnMouseDown(Sender, Button, Shift, X, Y);
372 end;
373 procedure TSynFacilEditor.edStatusChange(Sender: TObject; Changes: TSynStatusChanges);
374 //Cambia el estado del editor
375 begin
376 if scSelection in changes then begin //cambios en la selección
377 if OnSelectionChange<>nil then OnSelectionChange; //dispara eventos
378 if OnChangeEditorState<>nil then OnChangeEditorState; //para iniciar controles
379 end;
380 end;
381 procedure TSynFacilEditor.edChange(Sender: TObject);
382 begin
383 if fPanFileSaved <> nil then begin
384 if GetModified then fPanFileSaved.Text:=dic('Sin Guardar') else fPanFileSaved.Text:=dic('Guardado');
385 end;
386 //Ha habido cambio de contenido
387 if OnChangeEditorState<>nil then OnChangeEditorState; //para iniciar controles
388 //Pasa el evento
389 if OnEditChange <> nil then OnEditChange(Sender);
390 end;
391 procedure TSynFacilEditor.edCommandProcessed(Sender: TObject;
392 var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
393 begin
394 RefreshPanCursor;
395 linErr := 0; //para que quite la marca de fondo del error.
396 //Solo se notará cuando se refresque la línea en el editor.
397 end;
398 procedure TSynFacilEditor.edKeyDown(Sender: TObject; var Key: Word;
399 Shift: TShiftState);
400 begin
401 //Pasa el evento
402 if OnKeyDown <> nil then OnKeyDown(Sender, Key, Shift);
403 end;
404 procedure TSynFacilEditor.edKeyUp(Sender: TObject; var Key: Word;
405 Shift: TShiftState);
406 begin
407 //pasa el evento al resaltador por si necesita abrir el menú de completado
408 hl.KeyUp(Sender, Key, Shift);
409 //Pasa el evento
410 if OnKeyUp <> nil then OnKeyUp(Sender, Key, Shift);
411 end;
412
413 procedure TSynFacilEditor.edKeyPress(Sender: TObject; var Key: char);
414 begin
415 //Pasa evento
416 if OnKeyPress <> nil then OnKeyPress(Sender, Key);
417 end;
418
419 procedure TSynFacilEditor.edUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char
420 );
421 begin
422 //pasa el evento al resaltador por si necesita abrir el menú de completado
423 hl.UTF8KeyPress(Sender, UTF8Key);
424 //Pasa el evento
425 if OnUTF8KeyPress <> nil then OnUTF8KeyPress(Sender, UTF8Key);
426 end;
427
428 //Manejo de archivos recientes
429 procedure TSynFacilEditor.InitMenuRecents(menRecents0: TMenuItem; RecentList: TStringList;
430 MaxRecents0: integer=5);
431 //Configura un menú, con el historial de los archivos abiertos recientemente
432 //"nRecents", es el número de archivos recientes que se guardará
433 var
434 i: Integer;
435 begin
436 mnRecents := menRecents0;
437 RecentFiles := RecentList; //gaurda referencia a lista
438 MaxRecents := MaxRecents0;
439 //configura menú
440 mnRecents.Caption:= dic('&Recientes');
441 mnRecents.OnClick:=@ActualMenusReciente;
442 for i:= 1 to MaxRecents do begin
443 AddItemToMenu(mnRecents, '&'+IntToStr(i), @RecentClick);
444 end;
445 end;
446 procedure TSynFacilEditor.RecentClick(Sender: TObject);
447 //Se selecciona un archivo de la lista de recientes
448 begin
449 if SaveQuery then Exit; //Verifica cambios
450 LoadFile(MidStr(TMenuItem(Sender).Caption,4,150));
451 end;
452 procedure TSynFacilEditor.ActualMenusReciente(Sender: TObject);
453 {Actualiza el menú de archivos recientes con la lista de los archivos abiertos
454 recientemente. }
455 var
456 i: Integer;
457 begin
458 if mnRecents = nil then exit;
459 if RecentFiles = nil then exit;
460 //proteciión
461 if RecentFiles.Count = 0 then begin
462 mnRecents[0].Caption:=dic('No hay archivos');
463 mnRecents[0].Enabled:=false;
464 for i:= 1 to mnRecents.Count-1 do begin
465 mnRecents[i].Visible:=false;
466 end;
467 exit;
468 end;
469 //hace visible los ítems
470 mnRecents[0].Enabled:=true;
471 for i:= 0 to mnRecents.Count-1 do begin
472 if i<RecentFiles.Count then
473 mnRecents[i].Visible:=true
474 else
475 mnRecents[i].Visible:=false;
476 end;
477 //pone etiquetas a los menús, incluyendo un atajo numérico
478 for i:=0 to RecentFiles.Count-1 do begin
479 mnRecents[i].Caption := '&'+IntToStr(i+1)+' '+RecentFiles[i];
480 end;
481 end;
482 procedure TSynFacilEditor.AgregArcReciente(arch: string);
483 //Agrega el nombre de un archivo reciente
484 var hay: integer; //bandera-índice
485 i: integer;
486 begin
487 if RecentFiles = nil then exit;
488 //verifica si ya existe
489 hay := -1; //valor inicial
490 for i:= 0 to RecentFiles.Count-1 do
491 if RecentFiles[i] = arch then hay := i;
492 if hay = -1 then //no existe
493 RecentFiles.Insert(0,arch) //agrega al inicio
494 else begin //ya existe
495 RecentFiles.Delete(hay); //lo elimina
496 RecentFiles.Insert(0,arch); //lo agrega al inicio
497 end;
498 while RecentFiles.Count>MaxRecents do //mantiene tamaño máximo
499 RecentFiles.Delete(MaxRecents);
500 end;
501
502 procedure TSynFacilEditor.ReplaceDialog1Find(Sender: TObject);
503 var
504 encon : integer;
505 buscado : string;
506 opciones: TSynSearchOptions;
507 begin
508 buscado := ReplaceDialog1.FindText;
509 opciones := [];
510 if not(frDown in ReplaceDialog1.Options) then opciones += [ssoBackwards];
511 if frMatchCase in ReplaceDialog1.Options then opciones += [ssoMatchCase];
512 if frWholeWord in ReplaceDialog1.Options then opciones += [ssoWholeWord];
513 if frEntireScope in ReplaceDialog1.Options then opciones += [ssoEntireScope];
514
515 encon := ed.SearchReplace(buscado,'',opciones);
516 if encon = 0 then
517 MsgBox('No se encuentra: %s', [buscado]);
518 end;
519 procedure TSynFacilEditor.ReplaceDialog1Replace(Sender: TObject);
520 var
521 encon, r : integer;
522 buscado : string;
523 opciones: TSynSearchOptions;
524 begin
525 buscado := ReplaceDialog1.FindText;
526 opciones := [ssoFindContinue];
527 // opciones := [];
528 if not(frDown in ReplaceDialog1.Options) then opciones += [ssoBackwards];
529 if frMatchCase in ReplaceDialog1.Options then opciones += [ssoMatchCase];
530 if frWholeWord in ReplaceDialog1.Options then opciones += [ssoWholeWord];
531 if frEntireScope in ReplaceDialog1.Options then opciones += [ssoEntireScope];
532 if frReplaceAll in ReplaceDialog1.Options then begin
533 //se ha pedido reemplazar todo
534 encon := ed.SearchReplace(buscado,ReplaceDialog1.ReplaceText,
535 opciones+[ssoReplaceAll]); //reemplaza
536 msgbox('Se reemplazaron %d ocurrencias.',[encon]);
537 exit;
538 end;
539 //reemplazo con confirmación
540 ReplaceDialog1.CloseDialog;
541 encon := ed.SearchReplace(buscado,'',opciones); //búsqueda
542 while encon <> 0 do begin
543 //pregunta
544 r := Application.MessageBox(Pchar(dic('¿Reemplazar esta ocurrencia?')),
545 Pchar(dic('Reemplazo')), MB_YESNOCANCEL);
546 if r = IDCANCEL then exit;
547 if r = IDYES then begin
548 ed.TextBetweenPoints[ed.BlockBegin,ed.BlockEnd] := ReplaceDialog1.ReplaceText;
549 end;
550 //busca siguiente
551 encon := ed.SearchReplace(buscado,'',opciones); //búsca siguiente
552 end;
553 MsgBox('No se encuentra: %s', [buscado]);
554 end;
555 procedure TSynFacilEditor.SetModified(valor: boolean);
556 //Cambia el valor del campo "Modified", del editor
557 begin
558 if ed.Modified<> valor then begin
559 //se ha cambiado el estado de "Modificado"
560 ed.Modified := valor; //Fija valor
561 //dispara evento
562 if fPanFileSaved <> nil then begin
563 if GetModified then fPanFileSaved.Text:=dic('Sin Guardar') else fPanFileSaved.Text:=dic('Guardado');
564 end;
565 if OnChangeEditorState<>nil then OnChangeEditorState;
566 end;
567 end;
TSynFacilEditor.GetModifiednull568 function TSynFacilEditor.GetModified: boolean;
569 //Lee el valor del campo "Modified", del editor.
570 begin
571 Result := ed.Modified;
572 end;
573 //"Setters" de los paneles
574 procedure TSynFacilEditor.SetPanCursorPos(AValue: TStatusPanel);
575 begin
576 if FPanCursorPos=AValue then Exit;
577 fPanCursorPos:=AValue;
578 RefreshPanCursor;
579 end;
580 procedure TSynFacilEditor.SetPanFileSaved(AValue: TStatusPanel);
581 begin
582 if fPanFileSaved=AValue then Exit;
583 fPanFileSaved:=AValue;
584 if fPanFileSaved <> nil then begin
585 if GetModified then fPanFileSaved.Text:=dic('Sin Guardar') else fPanFileSaved.Text:=dic('Guardado');
586 end;
587 end;
588
589 procedure TSynFacilEditor.SetPanFileName(AValue: TStatusPanel);
590 begin
591 if fPanFileName=AValue then Exit;
592 fPanFileName:=AValue;
593 if fPanFileName <> nil then begin
594 fPanFileName.Text := SysToUTF8(FileName);
595 end;
596 end;
597 procedure TSynFacilEditor.SetPanForEndLin(AValue: TStatusPanel);
598 begin
599 if fPanForEndLin=AValue then Exit;
600 fPanForEndLin:=AValue;
601 if fPanForEndLin <> nil then begin
602 fPanForEndLin.Text:=LineEnd_To_Str(DelArc);
603 end;
604 end;
605 procedure TSynFacilEditor.SetPanCodifFile(AValue: TStatusPanel);
606 begin
607 if fPanCodifFile=AValue then Exit;
608 fPanCodifFile:=AValue;
609 if fPanCodifFile <> nil then begin
610 fPanCodifFile.Text:=CodArc;
611 end;
612 end;
613 procedure TSynFacilEditor.SetPanLangName(AValue: TStatusPanel);
614 begin
615 if fPanLangName=AValue then Exit;
616 fPanLangName:=AValue;
617 if fPanLangName<> nil then begin
618 fPanLangName.Text:= hl.LangName;
619 end;
620 end;
GetTextnull621 function TSynFacilEditor.GetText: string;
622 //Devuelve el contenido del editor, quitando el salto de línea final
623 begin
624 Result := ed.Text;
625 if AnsiEndsStr(LineEnding, Result) then begin
626 Setlength(Result, length(Result)-length(LineEnding));
627 end;
628 end;
629 procedure TSynFacilEditor.SetText(AValue: string);
630 //Fija el contenido del editor
631 begin
632 ed.Text:=AValue;
633 end;
634
635 procedure TSynFacilEditor.NewFile(QuerySave: boolean=true);
636 //Inicia al editor con un nuevo nombre de archivo
637 //"QuerySave" indica si se debe o no preguntar por archivo modificado
638 begin
639 if QuerySave then begin
640 if SaveQuery then Exit; //Verifica cambios
641 if Error<>'' then exit; //hubo error
642 end;
643 Error := ''; //limpia bandera de error
644 if extDef<> '' then //genera nombre por defecto
645 FileName := nomDef + '.' + extDef
646 else FileName := nomDef;
647 //verifica existencia
648 // if FileExists(Arc) then //ya existe
649 // AbrirArchivo(Arc) //lo abre
650 // else begin //no existe
651 // mnArGuarClick(nil); //Lo crea
652 DelArc := TAR_DOS; //inicia con Windows por defecto
653 CodArc := 'cp1252'; //inicia en formato Windows
654 ed.ClearAll; //limpia editor
655 ed.ClearUndo; //limpia acciones "deshacer"
656 SetModified(false);
657 ChangeFileInform; //actualiza
658 if OnChangeEditorState<>nil then OnChangeEditorState; //para iniciar controles
659 end;
660 procedure TSynFacilEditor.LoadFile(arc8: string);
661 //Carga el contenido de un archivo en el editor, analizando la codificación.
662 //Si ocurre algún error, muestra el mensaje en pantalla y actualiza "Error".
663 var
664 arc0: String;
665 begin
666 Error := ''; //limpia bandera de error
667 arc0 := UTF8ToSys(arc8); //pone en modo ANSI
668 //verifica existencia de archivo
669 if not FileExists(arc0) then begin
670 Error := dic('No se encuentra el archivo: ') + arc0;
671 msgErr(Error);
672 Exit; //sale
673 end;
674 //carga y lee formato
675 CargarArchivoLin(arc8, ed.Lines, DelArc, CodArc);
676 // StatusBar1.Panels[4].Text := CodArc; //actualiza codificación
677 FileName := arc0; //fija nombre de archivo de trabajo
678 SetModified(false); //Inicia estado
679 linErr := 0; //limpia línea marcada por si acaso
680 ChangeFileInform; //actualiza
681 if OnFileOpened<>nil then OnFileOpened; //dispara evento
682 AgregArcReciente(arc8); //agrega a lista de recientes
683 end;
684 procedure TSynFacilEditor.SaveFile;
685 //Guarda el contenido del editor en su archivo correspondiente
686 //Si ocurre algún error, muestra el mensaje en pantalla y actualiza "Error".
687 begin
688 Error := ''; //limpia bandera de error
689 try
690 GuardarArchivoLin(FileName, ed.Lines, DelArc, CodArc); //guarda en formato original
691 SetModified(false);
692 edChange(self); //para que actualice el panel fPanFileSaved
693 //se actualiza por si acaso, se haya guardado con otro nombre
694 ChangeFileInform; //actualiza
695 except
696 Error := dic('Error guardando archivo: ') + FileName;
697 msgErr(Error);
698 end;
699 end;
TSynFacilEditor.OpenDialognull700 function TSynFacilEditor.OpenDialog(OpenDialog1: TOpenDialog): boolean;
701 //Muestra el cuadro de diálogo para abrir un archivo, teniendo cuidado de
702 //pedir confirmación para grabar el contenido actual. Si hay error devuelve FALSE.
703 var arc0: string;
704 begin
705 Error := '';
706 if SaveQuery then exit(true); //Verifica cambios
707 if Error<>'' then exit(false); //hubo error
708 if not OpenDialog1.Execute then exit(true); //se canceló
709 arc0 := OpenDialog1.FileName;
710 LoadFile(arc0); //legalmente debería darle en UTF-8
711 Result := true; //sale sin incidencias
712 end;
SaveAsDialognull713 function TSynFacilEditor.SaveAsDialog(SaveDialog1: TSaveDialog): boolean;
714 //Guarda el contenido del editor, permitiendo cambiar el nombre con un diálogo.
715 //Si se ignora la acción, devuelve "true".
716 //Si ocurre algún error, muestra el mensaje en pantalla y actualiza "Error".
717 var
718 arc0: String;
719 resp: TModalResult;
720 begin
721 Result := false;
722 if not SaveDialog1.Execute then begin //se canceló
723 Result := true; //Sale con "true"
724 exit; //se canceló
725 end;
726 arc0 := SaveDialog1.FileName;
727 if FileExists(arc0) then begin
728 resp := MessageDlg('', dic('El archivo %s ya existe.' + LineEnding +
729 '¿Deseas sobreescribirlo?',[arc0]),
730 mtConfirmation, [mbYes, mbNo, mbCancel],0);
731 if (resp = mrCancel) or (resp = mrNo) then Exit;
732 end;
733 FileName := UTF8ToSys(arc0); //asigna nuevo nombre
734 if ExtractFileExt(FileName) = '' then FileName += '.'+extDef; //completa extensión
735 SaveFile; //lo guarda
736 end;
SaveQuerynull737 function TSynFacilEditor.SaveQuery: boolean;
738 //Verifica si es necesario guardar el archivo antes de ejecutar alguna oepración con el editor.
739 //Si se ignora la acción, devuelve "true".
740 //Si ocurre algún error, muestra el mensaje en pantalla y actualiza "Error".
741 var resp: integer;
742 begin
743 Result := false;
744 if ed = nil then begin
745 Error := dic('Error Interno: Editor no inicializado.');
746 msgErr(Error);
747 exit;
748 end;
749 if ed.Modified then begin
750 resp := MessageDlg('', dic('El archivo %s ha sido modificado.' + LineEnding +
751 '¿Deseas guardar los cambios?',[ExtractFileName(FileName)]),
752 mtConfirmation, [mbYes, mbNo, mbCancel],0);
753 if resp = mrCancel then begin
754 Result := true; //Sale con "true"
755 Exit;
756 end;
757 if resp = mrYes then begin //guardar
758 SaveFile; //Actualizar "Error"
759 end;
760 end;
761 end;
762 //Búsqueda y reemplazo
763 procedure TSynFacilEditor.FindDialog;
764 //Realiza una búsqueda en el texto del editor, usando el ´diálogo de búsqeudas.
765 begin
766 FindDialog1.OnFind:=@FindNextWord;
767 if ed.SelAvail then FindDialog1.FindText:=ed.SelText;
768 FindDialog1.Execute;
769 end;
770 procedure TSynFacilEditor.FindNextWord(Sender: TObject);
771 //Se ejecuta para encontrar el siguiente elemento. Es llamado por el evento FindText()
772 //de "FindDialog1", pero puede ser llamado también de forma directa.
773 var
774 encon : integer;
775 buscado : string;
776 opciones: TSynSearchOptions;
777 begin
778 buscado := FindDialog1.FindText;
779 opciones := [];
780 if not(frDown in FindDialog1.Options) then opciones += [ssoBackwards];
781 if frMatchCase in FindDialog1.Options then opciones += [ssoMatchCase];
782 if frWholeWord in FindDialog1.Options then opciones += [ssoWholeWord];
783 if frEntireScope in FindDialog1.Options then opciones += [ssoEntireScope];
784
785 encon := ed.SearchReplace(buscado,'',opciones);
786 if encon = 0 then
787 MsgBox('No se encuentra: %s', [buscado]);
788 end;
789 procedure TSynFacilEditor.ReplaceDialog;
790 //Realiza una búsqueda en el texto del editor, usando el ´diálogo de búsqeudas.
791 begin
792 ReplaceDialog1.OnFind:=@ReplaceDialog1Find;
793 ReplaceDialog1.OnReplace:=@ReplaceDialog1Replace;
794 if ed.SelAvail then ReplaceDialog1.FindText:=ed.SelText;
795 ReplaceDialog1.Execute;
796 end;
797 //herramientas
798 procedure TSynFacilEditor.TabToSpaces(fSelFuente: TfrmSelFuente);
799 //Convierte tabulaciones a espacios.
800 //Requiere un formaulario de tipo TfrmSelFuente para mostrar el dialogo.
801 var
802 i: integer;
803 begin
804 if ed.SelAvail then begin
805 fSelFuente.optLin.Enabled:=false;
806 fSelFuente.optSel.Enabled:=true;
807 fSelFuente.optSel.Checked := true;
808 end else begin
809 fSelFuente.optSel.Enabled:=false;
810 fSelFuente.optLin.Enabled := true;
811 fSelFuente.optLin.Checked := true;
812 end;
813 fSelFuente.ShowModal;
814 If fSelFuente.cancelado Then begin //se canceló
815 //no hace nada
816 end else If fSelFuente.optLin.Checked Then begin //línea
817 ed.LineText:=StringReplace(ed.LineText,#9, stringOfChar(' ',ed.TabWidth), [rfReplaceAll]);
818 end else If fSelFuente.optSel.Checked Then begin //seleción
819 ed.SelText:=StringReplace(ed.seltext,#9, stringOfChar(' ',ed.TabWidth), [rfReplaceAll]);;
820 end else begin //todo
821 for i := 0 to ed.Lines.Count-1 do
822 ed.Lines[i] := StringReplace(ed.Lines[i],#9, stringOfChar(' ',ed.TabWidth), [rfReplaceAll]);
823 End;
824 ed.ClearUndo; //porque no se puede deshacer
825 if OnChangeEditorState<>nil then OnChangeEditorState; //actualiza
826 end;
827 procedure TSynFacilEditor.TrimLines(fSelFuente: TfrmSelFuente);
828 //Quita espacios laterales
829 //Requiere un formaulario de tipo TfrmSelFuente para mostrar el dialogo.
830 var
831 i: integer;
832 f1: integer;
833 f2: integer;
834 begin
835 if ed.SelAvail then begin
836 fSelFuente.optLin.Enabled:=false;
837 fSelFuente.optSel.Enabled:=true;
838 fSelFuente.optSel.Checked := true;
839 end else begin
840 fSelFuente.optSel.Enabled:=false;
841 fSelFuente.optLin.Enabled := true;
842 fSelFuente.optLin.Checked := true;
843 end;
844 fSelFuente.ShowModal;
845 If fSelFuente.cancelado Then begin //se canceló
846 //no hace nada
847 end else If fSelFuente.optLin.Checked Then begin //línea
848 ed.LineText:=trim(ed.LineText);
849 end else If fSelFuente.optSel.Checked Then begin //seleción
850 f1 := ed.BlockBegin.y;
851 f2 := ed.BlockEnd.y;
852 for i := f1 to f2-1 do
853 ed.Lines[i-1] := trim(ed.Lines[i]);
854 end else begin //todo
855 for i := 0 to ed.Lines.Count-1 do
856 ed.Lines[i] := trim(ed.Lines[i]);
857 End;
858 ed.ClearUndo; //porque no se puede deshacer
859 if OnChangeEditorState<>nil then OnChangeEditorState; //actualiza
860 end;
FiltLinesnull861 function TSynFacilEditor.FiltLines(fSelFuente: TfrmSelFuente; sal: TStringList): boolean;
862 //Filtra líneas del contenido. Si se cancela la operación devuelve false.
863 var
864 i: integer;
865 s: string;
866 begin
867 Result := true; //por defecto
868 sal := TStringList.Create; //salida
869 fSelFuente.optLin.Enabled:=false;
870 if ed.SelAvail and (ed.BlockEnd.y - ed.BlockBegin.y >0) then begin
871 //hay selección de más de una línea
872 fSelFuente.optSel.Enabled:=true;
873 fSelFuente.optSel.Checked := true;
874 fSelFuente.ShowModal; //solo muestra aquí
875 If fSelFuente.cancelado Then exit; //se canceló
876 end else begin //no hay selección
877 fSelFuente.optTod.Checked := true;
878 // fSelFuente.ShowModal;
879 end;
880 If fSelFuente.optSel.Checked Then begin //seleción
881 s := InputBox('Filtrar líneas:','Ingrese texto: ','');
882 if s = '' then exit;
883 for i:= ed.BlockBegin.y to ed.BlockEnd.y do
884 if AnsiContainsText(ed.Lines[i],s) then sal.Add(ed.Lines[i]);
885 end Else begin //todo
886 if ed.BlockEnd.y = ed.BlockBegin.y then //hay texto seleccionado, suguiere
887 s := InputBox('Filtrar líneas:','Ingrese texto: ',ed.SelText)
888 else
889 s := InputBox('Filtrar líneas:','Ingrese texto: ','');
890 if s = '' then exit;
891 for i:= 0 to ed.Lines.Count-1 do
892 if AnsiContainsText(ed.Lines[i],s) then sal.Add(ed.Lines[i]);
893 End;
894 end;
895 //Funciones para cambio de Fin de Línea y Codificación
896 procedure TSynFacilEditor.ChangeEndLineDelim(nueFor: TLineEnd);
897 //Cambia el formato de salto de línea del contenido
898 begin
899 if DelArc <> nueFor then begin //verifica si hay cambio
900 DelArc := nueFor;
901 SetModified(true); //para indicar que algo ha cambiado
902 ChangeFileInform; //actualiza
903 end;
904 end;
905 procedure TSynFacilEditor.InitMenuLineEnding(mnLineEnding0: TMenuItem);
906 //Inicia un menú con los tipos de delimitador de línea que maneja la unidad, y les
907 //les asigna un evento para implementar el cambio.
908 begin
909 if mnLineEnding0 = nil then exit;
910 mnLineEnding := mnLineEnding0; //guarda referencia a menú
911 //configura menú
912 mnLineEnding.Caption:= dic('Fin de Línea');
913 mnLineEnding.Clear;
914 //llena opciones
915 AddItemToMenu(mnLineEnding, LineEnd_To_Str(TAR_UNIX), @LineEndingClick);
916 AddItemToMenu(mnLineEnding, LineEnd_To_Str(TAR_DOS), @LineEndingClick);
917 AddItemToMenu(mnLineEnding, LineEnd_To_Str(TAR_MAC), @LineEndingClick);
918 AddItemToMenu(mnLineEnding, LineEnd_To_Str(TAR_DESC), @LineEndingClick).Enabled:=false;
919 CheckOnlyOneItem(mnLineEnding, LineEnd_To_Str(delArc)); //actualiza
920 end;
921 procedure TSynFacilEditor.LineEndingClick(Sender: TObject);
922 var
923 it: TMenuItem;
924 delim: TLineEnd;
925 begin
926 it := TMenuItem(Sender);
927 delim := Str_To_LineEnd(it.Caption);
928 ChangeEndLineDelim(delim);
929 CheckOnlyOneItem(it); //marca menú
930 end;
931 procedure TSynFacilEditor.ChangeEncoding(nueCod: string);
932 //Cambia la codificación del archivo
933 begin
934 if CodArc <> nueCod then begin
935 CodArc := nueCod;
936 SetModified(true); //para indicar que algo ha cambiado
937 ChangeFileInform; //actualiza
938 end;
939 end;
940 procedure TSynFacilEditor.InitMenuEncoding(mnEncoding0: TMenuItem);
941 //Inicia un menú con los tipos de delimitador de línea que maneja la unidad, y les
942 //les asigna un evento para implementar el cambio.
943 begin
944 if mnEncoding0 = nil then exit;
945 mnEncoding := mnEncoding0; //guarda referencia a menú
946 //configura menú
947 mnEncoding.Caption:= dic('Codificación');
948 mnEncoding.Clear;
949 //llena opciones
950 AddItemToMenu(mnEncoding, 'utf8', @EncodingClick);
951 AddItemToMenu(mnEncoding, 'utf8bom', @EncodingClick);
952 AddItemToMenu(mnEncoding, 'cp1252', @EncodingClick);
953 AddItemToMenu(mnEncoding, 'ISO-8859-1', @EncodingClick);
954 AddItemToMenu(mnEncoding, '<Unknown>', @EncodingClick).Enabled:=false;
955 CheckOnlyOneItem(mnEncoding, codArc); //actualiza
956 end;
957 procedure TSynFacilEditor.EncodingClick(Sender: TObject);
958 var
959 it: TMenuItem;
960 begin
961 it := TMenuItem(Sender);
962 ChangeEncoding(it.Caption);
963 CheckOnlyOneItem(it); //marca menú
964 end;
965 procedure TSynFacilEditor.ChangeFileInform;
966 //Se debe llamar siempre que puede cambiar la información de nombre de archivo, tipo de
967 //delimitador de línea o tipo de codificación del archivo.
968 begin
969 //actualiza información en los paneles
970 if fPanFileName <> nil then begin
971 fPanFileName.Text := SysToUTF8(FileName);
972 end;
973 if fPanForEndLin <> nil then begin
974 fPanForEndLin.Text:=LineEnd_To_Str(DelArc);
975 end;
976 if fPanCodifFile <> nil then begin
977 fPanCodifFile.Text:=CodArc;
978 end;
979 //actualiza menús
980 CheckOnlyOneItem(mnLineEnding, LineEnd_To_Str(delArc));
981 CheckOnlyOneItem(mnEncoding, codArc);
982 //dispara evento
983 if OnChangeFileInform<>nil then OnChangeFileInform;
984 end;
985 procedure TSynFacilEditor.CloseCompletionWindow;
986 //Cierra la ventana de completado
987 begin
988 hl.CloseCompletionWindow;
989 end;
990 //Espejo de funciones comunes del editor
991 procedure TSynFacilEditor.Cut;
992 begin
993 ed.CutToClipboard;
994 end;
995 procedure TSynFacilEditor.Copy;
996 begin
997 ed.CopyToClipboard;
998 end;
999 procedure TSynFacilEditor.Paste;
1000 begin
1001 ed.PasteFromClipboard;
1002 end;
1003 procedure TSynFacilEditor.Undo;
1004 //Deshace una acción en el editor
1005 begin
1006 ed.Undo;
1007 end;
1008 procedure TSynFacilEditor.Redo;
1009 //Rehace una acción en el editor
1010 begin
1011 ed.Redo;
1012 end;
1013 procedure TSynFacilEditor.SelectAll;
1014 begin
1015 ed.SelectAll;
1016 end;
1017 //Lee estado
CanUndonull1018 function TSynFacilEditor.CanUndo: boolean;
1019 //Indica si Hay Algo por deshacer
1020 begin
1021 Result := ed.CanUndo;
1022 end;
CanRedonull1023 function TSynFacilEditor.CanRedo: boolean;
1024 //Indica si Hay Algo por rehacer
1025 begin
1026 Result := ed.CanRedo;
1027 end;
CanCopynull1028 function TSynFacilEditor.CanCopy: boolean;
1029 //Indica si hay algo por copiar
1030 begin
1031 Result := ed.SelAvail;
1032 end;
TSynFacilEditor.CanPastenull1033 function TSynFacilEditor.CanPaste: boolean;
1034 //Indica si Hay Algo por pegar
1035 begin
1036 Result := ed.CanPaste;
1037 end;
1038 procedure TSynFacilEditor.RefreshPanCursor;
1039 begin
1040 if fPanCursorPos <> nil then
1041 fPanCursorPos.Text:= dic('fil=%d, col=%d',[ed.CaretY, ed.CaretX]);
1042 end;
1043 procedure TSynFacilEditor.InitMenuLanguages(menLanguage0: TMenuItem; LangPath0: string);
1044 //Inicia un menú con la lista de archivos XML (que representan a lenguajes) que hay
1045 //en una carpeta en particular y les asigna un evento.
1046 var
1047 Hay: Boolean;
1048 SR : TSearchRec;
1049 begin
1050 if menLanguage0 = nil then exit;
1051 mnLanguages := menLanguage0; //guarda referencia a menú
1052 LangPath := LangPath0; //guarda ruta
1053 if (LangPath<>'') and (LangPath[length(LangPath)] <> DirectorySeparator) then
1054 LangPath+=DirectorySeparator;
1055 //configura menú
1056 mnLanguages.Caption:= dic('&Lenguajes');
1057 //explora archivos
1058 Hay := FindFirst(LangPath + '*.xml', faAnyFile - faDirectory, SR) = 0;
1059 while Hay do begin
1060 //encontró archivo
1061 AddItemToMenu(mnLanguages, '&'+ChangeFileExt(SR.name,''),@DoSelectLanguage);
1062 Hay := FindNext(SR) = 0;
1063 end;
1064 end;
1065 procedure TSynFacilEditor.DoSelectLanguage(Sender: TObject);
1066 //Se ha seleccionado un lenguaje desde el menú.
1067 var
1068 arcXML: String;
1069 it: TMenuItem;
1070 begin
1071 it := TMenuItem(Sender);
1072 arcXML := LangPath + RightStr(it.Caption,length(it.Caption)-1 ) + '.xml';
1073 hl.LoadFromFile(arcXML); //carga la sintaxis indicada
1074 if fPanLangName<> nil then begin
1075 fPanLangName.Text:= hl.LangName;
1076 end;
1077 CheckOnlyOneItem(it); //marca menú
1078 end;
1079 procedure TSynFacilEditor.CheckLanguageMenu(XMLfile: string);
1080 //Marca el ítem del menú de lenguaje que corresponde al nombre de archivo indicado.
1081 var
1082 XML: String;
1083 begin
1084 if mnLanguages = nil then exit;
1085 XML := ExtractFileName(XMLfile); //por si tenía ruta
1086 XML := ChangeFileExt(XML,'');
1087 CheckOnlyOneItem(mnLanguages, XML);
1088 end;
1089 procedure TSynFacilEditor.LoadSyntaxFromFile(XMLfile: string);
1090 //Carga un archivo de sintaxis en el editor.
1091 begin
1092 hl.LoadFromFile(XMLfile); //carga sintaxis
1093 if fPanLangName<> nil then begin
1094 fPanLangName.Text:= hl.LangName;
1095 end;
1096 //verifica si se puede marcar en el menú
1097 if mnLanguages = nil then exit; //no se ha confogurado menú
1098 if LangPath = ExtractFilePath(XMLfile) then begin
1099 //La ruta correponde a la definida para el menú.
1100 CheckLanguageMenu(XMLfile); //actualiza menú y panel
1101 end else begin
1102 //es una ruta distinta
1103 end;
1104 end;
1105 procedure TSynFacilEditor.LoadSyntaxFromPath(arc: string = '');
1106 //Carga la sintaxis de un archivo, buscando el archivo XML, apropiado en la ruta
1107 //de lengaujes definida con InitMenuLanguages().
1108 //Si no se indica el nombre del archivo, se usará el archivo actual
1109 var
1110 XML: String;
1111 begin
1112 if arc='' then begin
1113 arc := FileName;
1114 end;
1115 XML := hl.LoadSyntaxFromPath(arc,LangPath);
1116 //marca menú
1117 if XML<>'' then begin //encontró
1118 if fPanLangName<> nil then begin
1119 fPanLangName.Text:= hl.LangName;
1120 end;
1121 CheckLanguageMenu(XML); //actualiza menú
1122 exit;
1123 end;
1124 //No encontró archivo XML apropiado
1125 //Carga una sintaxis básica para limpiar la que pudiera haber
1126 hl.ClearMethodTables; //limpìa tabla de métodos
1127 hl.ClearSpecials; //para empezar a definir tokens
1128 //crea tokens por contenido
1129 hl.DefTokIdentif('[$A-Za-z_]', '[A-Za-z0-9_]*');
1130 hl.DefTokContent('[0-9]', '[0-9.]*', hl.tnNumber);
1131 hl.DefTokDelim('"','"', hl.tnString);
1132 hl.Rebuild; //reconstruye
1133 CheckLanguageMenu(''); //actualiza menú
1134 if fPanLangName<> nil then begin
1135 fPanLangName.Text:= dic('Sin lenguaje');
1136 end;
1137 end;
1138
1139 constructor TSynFacilEditor.Create(ed0: TsynEdit; nomDef0, extDef0: string);
1140 begin
1141 ed := ed0;
1142 hl := TSynFacilComplet.Create(ed.Owner); //crea resaltador
1143 hl.SelectEditor(ed); //inicia
1144 //intercepta eventos
1145 ed.OnChange:=@edChange; //necesita interceptar los cambios
1146 ed.OnStatusChange:=@edStatusChange;
1147 ed.OnMouseDown:=@edMouseDown;
1148 ed.OnKeyUp:=@edKeyUp; //para funcionamiento del completado
1149 ed.OnKeyDown:=@edKeyDown;
1150 ed.OnKeyPress:=@edKeyPress;
1151 ed.OnUTF8KeyPress:=@edUTF8KeyPress;
1152 ed.OnCommandProcessed:=@edCommandProcessed; //necesita para actualizar el cursor
1153 // RecentFiles := TStringList.Create;
1154 MaxRecents := 1; //Inicia con 1
1155 //guarda parámetros
1156 nomDef := nomDef0;
1157 extDef := extDef0;
1158 NewFile; //Inicia editor con archivo vacío
1159 end;
1160 destructor TSynFacilEditor.Destroy;
1161 begin
1162 hl.UnSelectEditor;
1163 hl.Free;
1164 // RecentFiles.Free;
1165 inherited Destroy;
1166 end;
1167 procedure TSynFacilEditor.SetLanguage(lang: string);
1168 //Rutina de traducción
1169 begin
1170 case lowerCase(lang) of
1171 'es': begin
1172 dicClear; //esttán en este idioma
1173 end;
1174 'en': begin
1175 //configura mensajes
1176 dicSet('fil=%d, col=%d','row=%d col=%d');
1177 dicSet('Guardado','Saved');
1178 dicSet('Sin Guardar','Modified');
1179 dicSet('El archivo %s ha sido modificado.' + LineEnding + '¿Deseas guardar los cambios?',
1180 'File %s, has been modified.' + LineEnding + 'Save?');
1181 dicSet('No se encuentra el archivo: ', 'File not found: ');
1182 dicSet('Error guardando archivo: ', 'Error saving file: ');
1183 dicSet('El archivo %s ya existe.' + LineEnding + '¿Deseas sobreescribirlo?',
1184 'File %s already exists.' + LineEnding + 'Overwrite?');
1185 dicSet('&Recientes', '&Recents');
1186 dicSet('&Lenguajes', '&Languages');
1187 dicSet('No hay archivos', 'No files');
1188 dicSet('Error Interno: Editor no inicializado.', 'Internal: Not initialized Editor.');
1189 dicSet('Sin lenguaje', 'No language');
1190 dicSet('¡Codificación de archivo desconocida!','Unknown file encoding');
1191 dicSet('Fin de Línea','Line Ending');
1192 dicSet('Codificación','Encoding');
1193 dicSet('No se encuentra: %s','No found: %s');
1194 dicSet('Se reemplazaron %d ocurrencias.','%d occurrences were replaced.');
1195 dicSet('¿Reemplazar esta ocurrencia?','Replace this?');
1196 dicSet('Reemplazo','Replace');
1197 end;
1198 end;
1199 end;
1200
1201 initialization
1202 //crea diálogos
1203 FindDialog1:= TFindDialog.Create(nil);
1204 ReplaceDialog1:= TReplaceDialog.Create(nil);
1205 finalization;
1206 ReplaceDialog1.Destroy;
1207 FindDialog1.Destroy;
1208 end.
1209
1210