diff --git a/examples/ansible/playbook.yml b/examples/ansible/playbook.yml new file mode 100644 index 0000000..295cee4 --- /dev/null +++ b/examples/ansible/playbook.yml @@ -0,0 +1,59 @@ +--- +# playbook.yml — Demonstrates core Ansible features for Doom Emacs workflow. +# +# Navigate: SPC s i (imenu for tasks), SPC s p (grep in project) +# Run: SPC m r (ansible-playbook), Lint: flycheck (ansible-lint) + +- name: Configure web server + hosts: webservers + become: true + + vars: + app_user: webapp + app_port: 8080 + packages: + - nginx + - python3 + - python3-pip + + handlers: + - name: Restart nginx + ansible.builtin.service: + name: nginx + state: restarted + + tasks: + - name: Install required packages + ansible.builtin.apt: + name: "{{ packages }}" + state: present + update_cache: true + + - name: Create application user + ansible.builtin.user: + name: "{{ app_user }}" + shell: /bin/bash + create_home: true + state: present + + - name: Deploy nginx config from template + ansible.builtin.template: + src: templates/nginx.conf.j2 + dest: /etc/nginx/sites-available/app.conf + owner: root + group: root + mode: "0644" + notify: Restart nginx + + - name: Enable site symlink + ansible.builtin.file: + src: /etc/nginx/sites-available/app.conf + dest: /etc/nginx/sites-enabled/app.conf + state: link + notify: Restart nginx + + - name: Ensure nginx is running + ansible.builtin.service: + name: nginx + state: started + enabled: true diff --git a/examples/docker/Dockerfile b/examples/docker/Dockerfile new file mode 100644 index 0000000..c87ffd4 --- /dev/null +++ b/examples/docker/Dockerfile @@ -0,0 +1,44 @@ +# Dockerfile — Multi-stage build for a Python application. +# +# Navigate: SPC s i (imenu), Lint: flycheck (hadolint) +# Build: SPC m b (podman build), Run: SPC m r (podman run) +# +# Build: podman build -t myapp:latest -f Dockerfile . +# Run: podman run --rm -p 8080:8080 myapp:latest + +# --- Stage 1: Build dependencies --- +FROM python:3.12-slim AS builder + +WORKDIR /build + +# Install dependencies first (layer caching) +COPY requirements.txt . +RUN pip install --no-cache-dir --prefix=/install -r requirements.txt + +# --- Stage 2: Runtime image --- +FROM python:3.12-slim AS runtime + +# Security: non-root user +RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser + +WORKDIR /app + +# Copy installed packages from builder +COPY --from=builder /install /usr/local + +# Copy application code +COPY app/ ./app/ +COPY main.py . + +# Set ownership +RUN chown -R appuser:appuser /app + +USER appuser + +EXPOSE 8080 + +# Healthcheck: verify the app responds +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')" || exit 1 + +ENTRYPOINT ["python", "main.py"] diff --git a/examples/go/main.go b/examples/go/main.go new file mode 100644 index 0000000..3ecec91 --- /dev/null +++ b/examples/go/main.go @@ -0,0 +1,105 @@ +// main.go — Demonstrates core Go features for Doom Emacs workflow. +// +// Navigate: C-M-a/e (function boundaries), SPC s i (imenu), gd (definition) +// Format: SPC m f (goimports), Run: SPC m r, Test: SPC m t, Build: SPC m b +package main + +import ( + "fmt" + "strings" + "sync" + "time" +) + +// Task represents a work item with priority. +type Task struct { + Title string + Priority int + Done bool +} + +// Summary returns a human-readable one-line description. +func (t *Task) Summary() string { + status := "TODO" + if t.Done { + status = "DONE" + } + return fmt.Sprintf("[%s] %s (p%d)", status, t.Title, t.Priority) +} + +// MarkDone marks the task as completed. +func (t *Task) MarkDone() { + t.Done = true +} + +// filterByPriority returns undone tasks with priority >= minPriority. +func filterByPriority(tasks []*Task, minPriority int) []*Task { + var result []*Task + for _, t := range tasks { + if !t.Done && t.Priority >= minPriority { + result = append(result, t) + } + } + return result +} + +// countWords demonstrates a goroutine + channel pattern. +// It counts words in each input string concurrently. +func countWords(inputs []string) map[string]int { + type result struct { + input string + count int + } + + ch := make(chan result, len(inputs)) + var wg sync.WaitGroup + + for _, s := range inputs { + wg.Add(1) + go func(text string) { + defer wg.Done() + // Simulate work + time.Sleep(10 * time.Millisecond) + ch <- result{input: text, count: len(strings.Fields(text))} + }(s) + } + + // Close channel after all goroutines finish + go func() { + wg.Wait() + close(ch) + }() + + counts := make(map[string]int) + for r := range ch { + counts[r.input] = r.count + } + return counts +} + +func main() { + tasks := []*Task{ + {Title: "Write tests", Priority: 2}, + {Title: "Update docs", Priority: 1}, + {Title: "Deploy v2", Priority: 2}, + } + + tasks[0].MarkDone() + + fmt.Println("Open tasks (priority >= 2):") + for _, t := range filterByPriority(tasks, 2) { + fmt.Println(" ", t.Summary()) + } + + // Goroutine demo + sentences := []string{ + "Go is a compiled language", + "Goroutines are lightweight threads", + "Channels enable safe communication", + } + counts := countWords(sentences) + fmt.Println("\nWord counts:") + for s, c := range counts { + fmt.Printf(" %q → %d words\n", s, c) + } +} diff --git a/examples/perl/example.pl b/examples/perl/example.pl new file mode 100644 index 0000000..74115d2 --- /dev/null +++ b/examples/perl/example.pl @@ -0,0 +1,65 @@ +#!/usr/bin/env perl +# example.pl — Demonstrates core Perl features for Doom Emacs workflow. +# Navigate: C-M-a/e (sub boundaries), SPC s i (imenu), gd (definition) +# Format: SPC m f (perltidy), Run: SPC m r, Debug: SPC m d + +use strict; +use warnings; +use Carp qw(croak); + +# --- Subroutine with documentation --- + +=head2 parse_config($filename) + +Reads a simple key=value config file. Returns a hashref. + +=cut + +sub parse_config { + my ($filename) = @_; + croak "Filename required" unless defined $filename; + + my %config; + open my $fh, '<', $filename + or die "Cannot open '$filename': $!\n"; + + while (my $line = <$fh>) { + chomp $line; + next if $line =~ /^\s*(?:#|$)/; # skip comments and blanks + if ($line =~ /^(\w+)\s*=\s*(.*)$/) { + $config{$1} = $2; + } + } + close $fh; + return \%config; +} + +# --- Array, hash, references --- + +my @languages = qw(Perl Python Go); +my %scores = (Perl => 95, Python => 90, Go => 88); + +my $lang_ref = \@languages; +my $score_ref = \%scores; + +printf "Languages: %s\n", join(', ', @{$lang_ref}); +printf "Perl score: %d\n", $score_ref->{Perl}; + +# --- Regex demo --- + +my $text = 'Error: connection refused at 2024-01-15 10:30:00'; +if ($text =~ /^(Error|Warning):\s+(.+?)\s+at\s+(\d{4}-\d{2}-\d{2})/) { + printf "Level: %s, Message: %s, Date: %s\n", $1, $2, $3; +} + +# --- Error handling with eval/die --- + +eval { + my $cfg = parse_config('/tmp/nonexistent.cfg'); + print "Loaded config\n"; +}; +if ($@) { + warn "Caught error: $@"; +} + +print "Done.\n"; diff --git a/examples/python/example.py b/examples/python/example.py new file mode 100644 index 0000000..398ac70 --- /dev/null +++ b/examples/python/example.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""example.py — Demonstrates core Python features for Doom Emacs workflow. + +Navigate: C-M-a/e (function boundaries), SPC s i (imenu), gd (definition) +Format: SPC m f (ruff format), Run: SPC m r +""" + +import argparse +from dataclasses import dataclass, field + + +@dataclass +class Task: + """A simple task with priority and tags.""" + + title: str + priority: int = 0 + tags: list[str] = field(default_factory=list) + done: bool = False + + def mark_done(self) -> None: + self.done = True + + def summary(self) -> str: + status = "DONE" if self.done else "TODO" + tag_str = ", ".join(self.tags) if self.tags else "none" + return f"[{status}] {self.title} (p{self.priority}, tags: {tag_str})" + + +def filter_tasks(tasks: list[Task], *, min_priority: int = 0) -> list[Task]: + """Return undone tasks with priority >= min_priority.""" + return [t for t in tasks if not t.done and t.priority >= min_priority] + + +def load_tasks_from_file(path: str) -> list[Task]: + """Load tasks from a simple text file (one title per line).""" + tasks: list[Task] = [] + try: + with open(path, encoding="utf-8") as fh: + for i, line in enumerate(fh): + title = line.strip() + if title: + tasks.append(Task(title=title, priority=i % 3)) + except FileNotFoundError: + print(f"File not found: {path}, using demo tasks") + tasks = [ + Task("Write tests", priority=2, tags=["dev"]), + Task("Update docs", priority=1, tags=["docs"]), + Task("Deploy v2", priority=2, tags=["ops", "dev"]), + ] + return tasks + + +def main() -> None: + parser = argparse.ArgumentParser(description="Task manager demo") + parser.add_argument("-f", "--file", default="tasks.txt", help="Task file") + parser.add_argument("-p", "--priority", type=int, default=1, help="Min priority") + args = parser.parse_args() + + tasks = load_tasks_from_file(args.file) + tasks[0].mark_done() + + important = filter_tasks(tasks, min_priority=args.priority) + print(f"Open tasks (priority >= {args.priority}):") + for task in important: + print(f" {task.summary()}") + + +if __name__ == "__main__": + main() diff --git a/examples/terraform/main.tf b/examples/terraform/main.tf new file mode 100644 index 0000000..8c4353f --- /dev/null +++ b/examples/terraform/main.tf @@ -0,0 +1,39 @@ +# main.tf — Demonstrates core Terraform features for Doom Emacs workflow. +# +# Navigate: SPC s i (imenu), SPC s p (grep in project) +# Format: SPC m f (terraform fmt), Init: SPC m i, Plan: SPC m p +# +# Uses null_resource for a provider-free demo. Replace with real providers +# (aws, azurerm, google) for actual infrastructure. + +terraform { + required_version = ">= 1.5" + required_providers { + null = { + source = "hashicorp/null" + version = "~> 3.0" + } + } +} + +# A null resource that runs a local command — useful for demos and provisioning +resource "null_resource" "hello" { + triggers = { + message = var.greeting_message + } + + provisioner "local-exec" { + command = "echo '${var.greeting_message}' > /tmp/terraform-hello.txt" + } +} + +# Output the greeting message for verification +output "greeting" { + description = "The greeting message written to file" + value = var.greeting_message +} + +output "environment" { + description = "Current deployment environment" + value = var.environment +} diff --git a/examples/terraform/variables.tf b/examples/terraform/variables.tf new file mode 100644 index 0000000..96cbbf2 --- /dev/null +++ b/examples/terraform/variables.tf @@ -0,0 +1,18 @@ +# variables.tf — Input variables for the Terraform demo. + +variable "greeting_message" { + description = "Message to write to the output file" + type = string + default = "Hello from Terraform!" +} + +variable "environment" { + description = "Deployment environment name" + type = string + default = "dev" + + validation { + condition = contains(["dev", "staging", "prod"], var.environment) + error_message = "Environment must be dev, staging, or prod." + } +} diff --git a/notes/developer-workflow.org b/notes/developer-workflow.org new file mode 100644 index 0000000..a440628 --- /dev/null +++ b/notes/developer-workflow.org @@ -0,0 +1,343 @@ +#+TITLE: Developer Workflow v Doom Emacs +#+AUTHOR: Martin Sukaný +#+DATE: [2026-02-24 Tue] +#+OPTIONS: toc:3 num:t +#+STARTUP: overview + +* Úvod + +Tento dokument popisuje kompletní vývojářský workflow v Doom Emacs pro jazyky a nástroje, které Martin používá: Perl, Python, Go, Ansible, Terraform a Podman/Dockerfile. Ke každému jazyku najdeš: co nainstalovat, klávesové zkratky, příklad workflow a odkaz na ukázkový soubor v =examples/=. + +* Instalace nástrojů + +Všechny nástroje se instalují přes Homebrew (macOS). Na Linuxu použij příslušný package manager. + +** Perl + +#+begin_src bash +brew install perl +cpanm Perl::Tidy Perl::Critic Perl::LanguageServer +#+end_src + +- =perltidy= — formatter (SPC m f) +- =perlcritic= — linter +- =Perl::LanguageServer= — LSP backend (volitelné) + +** Python + +#+begin_src bash +brew install python ruff pyright +#+end_src + +- =ruff= — ultra-rychlý linter + formatter +- =pyright= — type-checking LSP server + +** Go + +#+begin_src bash +brew install go gopls +go install golang.org/x/tools/cmd/goimports@latest +#+end_src + +- =gopls= — oficiální Go LSP +- =goimports= — formatter (gofmt + auto imports) + +** Ansible + +#+begin_src bash +brew install ansible ansible-lint +#+end_src + +- =ansible-lint= — linter pro playbooky (flycheck integrace) + +** Terraform + +#+begin_src bash +brew install terraform terraform-ls +#+end_src + +- =terraform-ls= — HashiCorp oficiální LSP server + +** Podman / Dockerfile + +#+begin_src bash +brew install podman hadolint +#+end_src + +- =hadolint= — Dockerfile linter (flycheck integrace) +- =podman= — Docker-kompatibilní container runtime (daemonless) + +* Keybindings přehled + +Všechny keybindings jsou pod =SPC m= (localleader) — aktivní pouze v příslušném major mode. + +| Jazyk | SPC m f | SPC m r | SPC m t / b | SPC m d | SPC m i / p | +|------------+-----------------+------------------+------------------+-----------+------------------| +| Perl | perltidy format | perl run | — | perldb | — | +| Python | ruff format | python3 run | — | M-x pdb | — | +| Go | goimports | go run | go test / build | M-x dlv | — | +| Ansible | — | ansible-playbook | — | — | — | +| Terraform | terraform fmt | — | — | — | init / plan | +| Dockerfile | — | podman run | podman build | — | — | + +Obecné navigační zkratky (všechny jazyky): + +| Zkratka | Akce | +|-------------+-----------------------------------| +| =C-M-a= | Začátek funkce/subroutine | +| =C-M-e= | Konec funkce/subroutine | +| =SPC s i= | Imenu — seznam funkcí v souboru | +| =gd= | Go to definition (LSP/tags) | +| =] e= / =[ e= | Další/předchozí flycheck error | +| =SPC s p= | Grep v projektu (ripgrep) | +| =SPC p f= | Najít soubor v projektu | + +* Perl — workflow + +** Co nainstalovat + +#+begin_src bash +brew install perl +cpanm Perl::Tidy Perl::Critic Perl::LanguageServer +#+end_src + +** Keybindings + +| Zkratka | Akce | +|-----------+-----------------------------| +| =SPC m f= | Formátování přes perltidy | +| =SPC m r= | Spustit aktuální soubor | +| =SPC m d= | Spustit Perl debugger | +| =C-M-a= | Skok na začátek subroutine | +| =C-M-e= | Skok na konec subroutine | +| =SPC s i= | Imenu — seznam subs | + +** Příklad workflow + +1. Otevři soubor: =SPC p f= → vyber =example.pl= +2. Navigace po subs: =SPC s i= → vyber subroutine ze seznamu +3. Pohyb mezi subs: =C-M-a= (začátek), =C-M-e= (konec) +4. Formátování: =SPC m f= (perltidy celý buffer) +5. Spuštění: =SPC m r= — otevře compile buffer s výstupem +6. Debug: =SPC m d= → zadej soubor → v kódu přidej =$DB::single = 1;= pro breakpoint +7. Chyby: =] e= / =[ e= pro navigaci flycheck errors + +** Ukázkový soubor + +Viz =[[file:../examples/perl/example.pl][examples/perl/example.pl]]= — demonstruje strict/warnings, subroutines, hashe, regex, file I/O a error handling. + +* Python — workflow + +** Co nainstalovat + +#+begin_src bash +brew install python ruff pyright +pip install pyvenv # volitelné, pro virtualenv management +#+end_src + +** Keybindings + +| Zkratka | Akce | +|-----------+-----------------------------| +| =SPC m f= | Formátování přes ruff | +| =SPC m r= | Spustit aktuální soubor | +| =gd= | Go to definition (pyright) | +| =K= | Hover docs (LSP) | +| =SPC s i= | Imenu — seznam tříd/funkcí | + +** Příklad workflow + +1. Otevři projekt: =SPC p p= → vyber Python projekt +2. Virtual env: =M-x pyvenv-activate= → vyber venv adresář +3. Navigace: =SPC s i= pro přehled tříd a funkcí +4. LSP: =gd= (definice), =K= (docs), =gr= (references) +5. Format: =SPC m f= — ruff format na celý soubor +6. Run: =SPC m r= — spustí =python3 buffer.py= v compile bufferu +7. Debug: =M-x pdb= → zadej =python3 -m pdb soubor.py= +8. Chyby: =] e= / =[ e= pro flycheck (ruff lint) + +** Ukázkový soubor + +Viz =[[file:../examples/python/example.py][examples/python/example.py]]= — demonstruje type hints, dataclass, list comprehension, argparse a exception handling. + +* Go — workflow + +** Co nainstalovat + +#+begin_src bash +brew install go gopls +go install golang.org/x/tools/cmd/goimports@latest +#+end_src + +** Keybindings + +| Zkratka | Akce | +|-----------+------------------------------| +| =SPC m f= | Formátování (goimports) | +| =SPC m r= | go run aktuální soubor | +| =SPC m t= | go test ./... | +| =SPC m b= | go build ./... | +| =gd= | Go to definition (gopls) | +| =K= | Hover docs (gopls) | + +** Příklad workflow + +1. Nový projekt: =go mod init myproject= v terminálu +2. Otevři: =SPC p f= → =main.go= +3. LSP automaticky: gopls se spustí, poskytuje completion, diagnostiku, navigaci +4. Píšeš kód: goimports automaticky doplní importy při uložení +5. Run: =SPC m r= → =go run main.go= +6. Test: =SPC m t= → =go test ./...= +7. Build: =SPC m b= → =go build ./...= + +** Ukázkový soubor + +Viz =[[file:../examples/go/main.go][examples/go/main.go]]= — demonstruje struct, methods, error handling, goroutine a channel. + +* Ansible — workflow + +** Co nainstalovat + +#+begin_src bash +brew install ansible ansible-lint +#+end_src + +** Keybindings + +| Zkratka | Akce | +|-----------+-------------------------------| +| =SPC m r= | Spustit ansible-playbook | +| =] e= | Další ansible-lint chyba | +| =SPC s p= | Grep v projektu (role, vars) | + +** Příklad workflow + +1. Otevři playbook: =SPC p f= → =playbook.yml= +2. Yaml-mode se aktivuje automaticky, ansible-lint přes flycheck +3. Navigace: =SPC s i= pro imenu (task names) +4. Spuštění: =SPC m r= — spustí =ansible-playbook playbook.yml= +5. Lint chyby: =] e= / =[ e= pro navigaci + +** Ukázkový soubor + +Viz =[[file:../examples/ansible/playbook.yml][examples/ansible/playbook.yml]]= — demonstruje apt install, user create, template copy, handlers a vars. + +* Terraform — workflow + +** Co nainstalovat + +#+begin_src bash +brew install terraform terraform-ls +#+end_src + +** Keybindings + +| Zkratka | Akce | +|-----------+-------------------------| +| =SPC m f= | terraform fmt | +| =SPC m i= | terraform init | +| =SPC m p= | terraform plan | +| =gd= | Go to definition (LSP) | + +** Příklad workflow + +1. Nový projekt: vytvoř adresář, =main.tf= + =variables.tf= +2. Init: =SPC m i= — stáhne providery +3. LSP (terraform-ls): autocompletion pro resource typy, atributy, variables +4. Format: =SPC m f= — terraform fmt (kanonický styl) +5. Plan: =SPC m p= — ukáže co se změní +6. Apply: v terminálu =terraform apply= + +** Ukázkové soubory + +Viz =[[file:../examples/terraform/main.tf][examples/terraform/main.tf]]= a =[[file:../examples/terraform/variables.tf][examples/terraform/variables.tf]]= — demonstrují null provider, resource, variable, output a validation. + +* Podman / Dockerfile — workflow + +** Co nainstalovat + +#+begin_src bash +brew install podman hadolint +podman machine init # jednorázově +podman machine start +#+end_src + +** Keybindings + +| Zkratka | Akce | +|-----------+-----------------------------------| +| =SPC m b= | podman build (zeptá se na tag) | +| =SPC m r= | podman run (zeptá se na image) | +| =] e= | Další hadolint chyba | + +** Příklad workflow + +1. Otevři =Dockerfile=: dockerfile-mode se aktivuje automaticky +2. Hadolint: flycheck ukazuje best practices (DL3008, DL3059 atd.) +3. Build: =SPC m b= → zadej tag (např. =myapp:latest=) → compile buffer +4. Run: =SPC m r= → zadej image name → spustí container + +** Ukázkový soubor + +Viz =[[file:../examples/docker/Dockerfile][examples/docker/Dockerfile]]= — demonstruje multi-stage build, non-root user, HEALTHCHECK a layer caching. + +* Go — učení (začátečník) + +** Základní kroky + +1. Vytvoř projekt: + #+begin_src bash + mkdir myproject && cd myproject + go mod init myproject + #+end_src + +2. Struktura: + #+begin_example + myproject/ + ├── go.mod + ├── main.go # vstupní bod + ├── internal/ # interní balíčky + │ └── handler.go + └── pkg/ # veřejné balíčky + └── utils.go + #+end_example + +3. Spusť: =go run main.go= (nebo =SPC m r= v Emacsu) +4. Test: =go test ./...= (nebo =SPC m t=) +5. Build: =go build -o myapp= (nebo =SPC m b=) + +** Klíčové koncepty + +- =package main= + =func main()= = vstupní bod +- Error handling: =if err != nil { return err }= (žádné exceptions) +- Goroutines: =go func()= pro souběžnost +- Channels: =ch := make(chan int)= pro komunikaci mezi goroutines +- Interfaces: implicitní implementace (duck typing) + +** Příklad + +Viz =[[file:../examples/go/main.go][examples/go/main.go]]= pro funkční ukázku všech konceptů. + +* Obecné tipy + +| Zkratka | Akce | +|---------------+-----------------------------------------| +| =SPC s p= | Grep v projektu (ripgrep) | +| =SPC p f= | Najít soubor v projektu | +| =SPC p p= | Přepnout projekt | +| =SPC g g= | Magit — git status | +| =SPC g B= | Git blame | +| =C-M-a= / =C-M-e= | Pohyb po funkcích (všechny jazyky) | +| =] e= / =[ e= | Flycheck: další/předchozí error | +| =SPC c x= | Flycheck: seznam všech errors | +| =SPC b b= | Přepnout buffer | +| =SPC w v= | Vertikální split | +| =SPC o t= | Otevřít terminál (vterm) | + +** Compile buffer + +Všechny =SPC m r/t/b= příkazy používají Emacs =compile= — výstup se zobrazí v compile bufferu. Klávesy v compile bufferu: + +- =g= — znovu spustit +- =q= — zavřít +- =RET= na error řádku — skok na zdrojový kód