Implement AsciiDoc and TipTap conversion logic, including new Admonition node and CodeBlock extension; add DiffViewer and HistoryPanel components for document version comparison; introduce password hashing utility with SHA-256.

This commit is contained in:
2026-04-12 22:28:15 +02:00
parent 05b773c14c
commit 376b946e73
22 changed files with 2767 additions and 323 deletions

View File

@@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
)
@@ -49,28 +50,43 @@ func (r *Repo) Commit(path, content, message, author, email string) error {
return err
}
// Log returns the commit history for a file.
// Log returns the commit history for a file, including added/removed line counts.
func (r *Repo) Log(path string) ([]LogEntry, error) {
out, err := r.run("log", "--format=%H|%an|%ae|%ai|%s", "--", path)
out, err := r.run("log", "--format=COMMIT|%H|%an|%ae|%ai|%s", "--numstat", "--", path)
if err != nil {
return nil, err
}
var entries []LogEntry
var current *LogEntry
for _, line := range strings.Split(strings.TrimSpace(out), "\n") {
if line == "" {
continue
}
parts := strings.SplitN(line, "|", 5)
if len(parts) == 5 {
entries = append(entries, LogEntry{
Hash: parts[0],
Author: parts[1],
Email: parts[2],
Date: parts[3],
Subject: parts[4],
})
if strings.HasPrefix(line, "COMMIT|") {
if current != nil {
entries = append(entries, *current)
}
parts := strings.SplitN(strings.TrimPrefix(line, "COMMIT|"), "|", 5)
if len(parts) == 5 {
current = &LogEntry{
Hash: parts[0],
Author: parts[1],
Email: parts[2],
Date: parts[3],
Subject: parts[4],
}
}
} else if current != nil && strings.Contains(line, "\t") {
// numstat line: "added\tremoved\tfilename"
fields := strings.SplitN(line, "\t", 3)
if len(fields) == 3 {
added, _ := strconv.Atoi(fields[0])
removed, _ := strconv.Atoi(fields[1])
current.Added += added
current.Removed += removed
}
}
}
if current != nil {
entries = append(entries, *current)
}
return entries, nil
}
@@ -85,12 +101,34 @@ func (r *Repo) Show(hash, path string) (string, error) {
return r.run("show", fmt.Sprintf("%s:%s", hash, path))
}
// HasUncommitted returns true if the working tree contains untracked or
// modified files that have not yet been committed.
func (r *Repo) HasUncommitted() bool {
out, err := r.run("status", "--porcelain")
return err == nil && strings.TrimSpace(out) != ""
}
// CommitAll stages every file in the repo root and creates a commit.
func (r *Repo) CommitAll(message, author, email string) error {
if _, err := r.run("add", "-A"); err != nil {
return err
}
_, err := r.run(
"-c", fmt.Sprintf("user.name=%s", author),
"-c", fmt.Sprintf("user.email=%s", email),
"commit", "-m", message,
)
return err
}
type LogEntry struct {
Hash string
Author string
Email string
Date string
Subject string
Added int
Removed int
}
func writeFile(path, content string) error {