feat(apk): notes de commandes, une commande copiee a la fois
Bloc Commands en tete d'une note "commands", groupe par groupe, avec un bouton copier. ParseCommandNote est le portage du decoupage du poste (groupes, lignes continuees). La copie passe par un rang, comme les autres lignes du detail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,19 @@ function VaultToJson(AVault: TVault): string;
|
||||
/// Les lignes d'une entree, dans l'ordre d'affichage.
|
||||
function DetailToJson(const AEntry: TVaultEntry): string;
|
||||
|
||||
type
|
||||
TCommandItem = record
|
||||
Group, Cmd: string;
|
||||
end;
|
||||
|
||||
/// NOTE DE COMMANDES (modele "commands"), meme regle que le poste
|
||||
/// (js/app.js parseCommandNote) : "# titre" ouvre un groupe, chaque autre ligne
|
||||
/// non vide est une commande ; une ligne finie par \, ` ou ^ se recolle a la
|
||||
/// suivante, sur UNE ligne. Une ligne vide ou la fin du texte termine la
|
||||
/// commande en cours.
|
||||
function ParseCommandNote(const AText: string): TArray<TCommandItem>;
|
||||
function IsCommandNote(const AEntry: TVaultEntry): Boolean;
|
||||
|
||||
/// Une ligne du detail par son rang, dans le MEME ordre que DetailToJson : la
|
||||
/// page renvoie un rang, jamais une valeur, et Delphi relit le clair chez lui.
|
||||
/// Faux si le rang ne designe rien.
|
||||
@@ -245,6 +258,49 @@ begin
|
||||
Result := LRows;
|
||||
end;
|
||||
|
||||
function IsCommandNote(const AEntry: TVaultEntry): Boolean;
|
||||
begin
|
||||
Result := AEntry.IsNote and SameText(AEntry.Template, 'commands');
|
||||
end;
|
||||
|
||||
function ParseCommandNote(const AText: string): TArray<TCommandItem>;
|
||||
var
|
||||
LGroup, LPending, LLine, LPart: string;
|
||||
LCont: Boolean;
|
||||
|
||||
procedure Flush;
|
||||
begin
|
||||
if LPending <> '' then
|
||||
begin
|
||||
SetLength(Result, Length(Result) + 1);
|
||||
Result[High(Result)].Group := LGroup;
|
||||
Result[High(Result)].Cmd := LPending;
|
||||
end;
|
||||
LPending := '';
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := nil;
|
||||
LGroup := '';
|
||||
LPending := '';
|
||||
for LLine in AText.Replace(#13, '').Split([#10]) do
|
||||
begin
|
||||
var LTrim := LLine.Trim;
|
||||
if LTrim = '' then begin Flush; Continue; end;
|
||||
if (LPending = '') and LTrim.StartsWith('#') then
|
||||
begin
|
||||
LGroup := LTrim.TrimLeft(['#']).Trim;
|
||||
Continue;
|
||||
end;
|
||||
LCont := CharInSet(LTrim[High(LTrim)], ['\', '`', '^']);
|
||||
if LCont then LPart := Copy(LTrim, 1, Length(LTrim) - 1).TrimRight
|
||||
else LPart := LTrim;
|
||||
if LPending = '' then LPending := LPart else LPending := LPending + ' ' + LPart;
|
||||
if not LCont then Flush;
|
||||
end;
|
||||
Flush;
|
||||
end;
|
||||
|
||||
function DetailToJson(const AEntry: TVaultEntry): string;
|
||||
var
|
||||
LRoot: TJSONObject;
|
||||
@@ -278,6 +334,21 @@ begin
|
||||
if LRows[I].Multiline then LObj.AddPair('m', TJSONBool.Create(True));
|
||||
LArr.AddElement(LObj);
|
||||
end;
|
||||
// La liste des commandes, pour l'affichage. La copie passe par un rang
|
||||
// (copy?f=cmd&k=), comme les lignes : Delphi relit le clair chez lui.
|
||||
if IsCommandNote(AEntry) then
|
||||
begin
|
||||
var LCmds := ParseCommandNote(AEntry.Password);
|
||||
var LCArr := TJSONArray.Create;
|
||||
LRoot.AddPair('cmds', LCArr);
|
||||
for I := 0 to High(LCmds) do
|
||||
begin
|
||||
LObj := TJSONObject.Create;
|
||||
LObj.AddPair('g', LCmds[I].Group);
|
||||
LObj.AddPair('c', LCmds[I].Cmd);
|
||||
LCArr.AddElement(LObj);
|
||||
end;
|
||||
end;
|
||||
Result := LRoot.ToJSON;
|
||||
finally
|
||||
LRoot.Free;
|
||||
|
||||
Reference in New Issue
Block a user