From dc4a5654abdbbc9072d08f864a2b7855d3001d0c Mon Sep 17 00:00:00 2001 From: Glenn Date: Sun, 28 Sep 2025 11:27:10 +0300 Subject: [PATCH] Add new blog post: Development Environment Evolution with Guix Home - New post: 2025-09-28-dev-environment-evolution-guix-home.md - Documents transition to Guix Home on WSL2 Ubuntu - Covers custom Emacs 31.0.50 build and Scheme development setup - Includes real Guix Home configuration with guile-hoot - Updated build and deploy scripts with line ending fixes - Regenerated RSS feed and site index with new post --- README.md | 9 +- build.sh | 344 ++-- .../2025-04-04-one-year-of-craftering.html | 295 ++- ...8-dev-environment-evolution-guix-home.html | 273 +++ ...-28-dev-environment-evolution-guix-home.md | 222 +++ deploy.sh | 234 +-- .../2025-04-04-one-year-of-craftering.html | 148 ++ ...8-dev-environment-evolution-guix-home.html | 273 +++ deploy/feed.xml | 1164 ++---------- deploy/index.html | 382 ++-- deploy/js/md-to-html.js | 70 +- dist/styles.css | 1598 +---------------- feed.xml | 1199 ++----------- index.html | 401 +++-- src/js/md-to-html.js | 70 +- website-deploy.zip | Bin 120505 -> 120359 bytes 16 files changed, 2228 insertions(+), 4454 deletions(-) create mode 100644 content/posts/2025-09-28-dev-environment-evolution-guix-home.html create mode 100644 content/posts/2025-09-28-dev-environment-evolution-guix-home.md create mode 100644 deploy/content/posts/2025-04-04-one-year-of-craftering.html create mode 100644 deploy/content/posts/2025-09-28-dev-environment-evolution-guix-home.html diff --git a/README.md b/README.md index 4354726..8f3e923 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,14 @@ Visit the live site at [https://glenneth.org](https://glenneth.org) ``` 3. Start the development server: ```bash - ./serve.sh + # Option 1: Build and serve with auto-reload + ./build.sh --serve + + # Option 2: Development mode with CSS watching + npm run dev ``` - This will start a live-server instance with auto-reload on port 3001. + - `./build.sh --serve` starts a live-server on port 9000 (or next available port) + - `npm run dev` runs Tailwind CSS in watch mode + live-server on port 3000 ## Content Management ### Adding New Blog Posts diff --git a/build.sh b/build.sh index b35663b..bd693cc 100755 --- a/build.sh +++ b/build.sh @@ -1,172 +1,172 @@ -#!/bin/bash - -# Default settings -PORT=9000 # Changed default to avoid common conflicts -SERVE=false -DEBUG=false - -# Parse command line arguments -while [[ "$#" -gt 0 ]]; do - case $1 in - --serve) SERVE=true ;; - --port) PORT="$2"; shift ;; - --debug) DEBUG=true ;; - *) echo "Unknown parameter: $1"; exit 1 ;; - esac - shift -done - -# Function to log debug messages -log_debug() { - if [ "$DEBUG" = true ]; then - echo "[DEBUG] $1" - fi -} - -# Function to cleanup and exit -cleanup() { - echo -e "\nShutting down server..." - pkill -f "live-server.*:$PORT" 2>/dev/null - exit 0 -} - -# Function to check if a port is in use -check_port() { - local port=$1 - nc -z localhost "$port" >/dev/null 2>&1 - if [ $? -eq 0 ]; then - return 0 # Port is in use - fi - return 1 # Port is free -} - -# Function to find next available port -find_available_port() { - local port=$1 - local max_port=$((port + 100)) # Don't search indefinitely - - while [ "$port" -lt "$max_port" ]; do - if ! check_port "$port"; then - echo "$port" - return 0 - fi - port=$((port + 1)) - done - - echo "Error: No available ports found between $1 and $max_port" >&2 - exit 1 -} - -# Set up trap for Ctrl+C (SIGINT) if serving -if [ "$SERVE" = true ]; then - trap cleanup SIGINT -fi - -# Directory structure -MD_DIR="content/posts" -DEPLOY_DIR="deploy" -POSTS_DEPLOY_DIR="$DEPLOY_DIR/content/posts" -DIST_DIR="$DEPLOY_DIR/dist" -SRC_DIR="src" - -# Ensure all required directories exist -dirs_to_create=( - "$MD_DIR" - "$DEPLOY_DIR" - "$POSTS_DEPLOY_DIR" - "$DIST_DIR" - "$SRC_DIR" -) - -for dir in "${dirs_to_create[@]}"; do - if [ ! -d "$dir" ]; then - echo "Creating directory: $dir" - mkdir -p "$dir" - fi -done - -# Build CSS first to ensure styles are available -echo "Building CSS..." -if ! npm run build; then - echo "Error: Failed to build CSS" - exit 1 -fi - -echo "Checking for new markdown files..." -CONVERTED_COUNT=0 - -# Loop through all markdown files -for md_file in "$MD_DIR"/*.md; do - # Skip if no markdown files found - [[ -e "$md_file" ]] || continue - - base_name=$(basename "$md_file") - html_file="$POSTS_DEPLOY_DIR/${base_name%.md}.html" - local_html_file="$MD_DIR/${base_name%.md}.html" - - log_debug "Processing $base_name" - - # Check if HTML file doesn't exist or markdown file is newer - if [[ ! -f "$html_file" ]] || [[ "$md_file" -nt "$html_file" ]]; then - echo "Converting $base_name to HTML..." - if ! node "$SRC_DIR/js/md-to-html.js" "$md_file" "$html_file"; then - echo "Error: Failed to convert $base_name to HTML" - exit 1 - fi - cp "$html_file" "$local_html_file" - ((CONVERTED_COUNT++)) - fi -done - -echo "Converted $CONVERTED_COUNT new or modified files" - -# Update summaries in index.html -echo "Updating blog post summaries in index.html..." -if ! npm run update-summaries; then - echo "Error: Failed to update summaries" - exit 1 -fi - -# Generate RSS feed -echo "Generating RSS feed..." -if ! node "$SRC_DIR/js/generate-rss.js"; then - echo "Error: Failed to generate RSS feed" - exit 1 -fi - -# Copy necessary files to deploy directory -echo "Copying files to deploy directory..." -cp index.html "$DEPLOY_DIR/" -cp -r dist/* "$DEPLOY_DIR/dist/" - -# If --serve flag is provided, start the server -if [ "$SERVE" = true ]; then - # Find available port if specified port is in use - FINAL_PORT=$(find_available_port "$PORT") - - echo "Starting local server on port $FINAL_PORT..." - echo "Visit http://localhost:$FINAL_PORT to view your site" - echo "Press Ctrl+C to stop the server" - - # Copy deploy files to root for local development - cp -r "$DEPLOY_DIR"/* . - - # Ensure live-server exists - if [ ! -f "./node_modules/.bin/live-server" ]; then - echo "Error: live-server not found. Please run 'npm install' first." - exit 1 - fi - - # Start live-server with specific options - ./node_modules/.bin/live-server \ - --port="$FINAL_PORT" \ - --no-browser \ - --watch="*.html,*.css,content/**/*.html" \ - --wait=50 \ - --quiet \ - --ignore=node_modules \ - . - - # Keep script running until Ctrl+C - wait -fi +#!/bin/bash + +# Default settings +PORT=9000 # Changed default to avoid common conflicts +SERVE=false +DEBUG=false + +# Parse command line arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --serve) SERVE=true ;; + --port) PORT="$2"; shift ;; + --debug) DEBUG=true ;; + *) echo "Unknown parameter: $1"; exit 1 ;; + esac + shift +done + +# Function to log debug messages +log_debug() { + if [ "$DEBUG" = true ]; then + echo "[DEBUG] $1" + fi +} + +# Function to cleanup and exit +cleanup() { + echo -e "\nShutting down server..." + pkill -f "live-server.*:$PORT" 2>/dev/null + exit 0 +} + +# Function to check if a port is in use +check_port() { + local port=$1 + nc -z localhost "$port" >/dev/null 2>&1 + if [ $? -eq 0 ]; then + return 0 # Port is in use + fi + return 1 # Port is free +} + +# Function to find next available port +find_available_port() { + local port=$1 + local max_port=$((port + 100)) # Don't search indefinitely + + while [ "$port" -lt "$max_port" ]; do + if ! check_port "$port"; then + echo "$port" + return 0 + fi + port=$((port + 1)) + done + + echo "Error: No available ports found between $1 and $max_port" >&2 + exit 1 +} + +# Set up trap for Ctrl+C (SIGINT) if serving +if [ "$SERVE" = true ]; then + trap cleanup SIGINT +fi + +# Directory structure +MD_DIR="content/posts" +DEPLOY_DIR="deploy" +POSTS_DEPLOY_DIR="$DEPLOY_DIR/content/posts" +DIST_DIR="$DEPLOY_DIR/dist" +SRC_DIR="src" + +# Ensure all required directories exist +dirs_to_create=( + "$MD_DIR" + "$DEPLOY_DIR" + "$POSTS_DEPLOY_DIR" + "$DIST_DIR" + "$SRC_DIR" +) + +for dir in "${dirs_to_create[@]}"; do + if [ ! -d "$dir" ]; then + echo "Creating directory: $dir" + mkdir -p "$dir" + fi +done + +# Build CSS first to ensure styles are available +echo "Building CSS..." +if ! npm run build; then + echo "Error: Failed to build CSS" + exit 1 +fi + +echo "Checking for new markdown files..." +CONVERTED_COUNT=0 + +# Loop through all markdown files +for md_file in "$MD_DIR"/*.md; do + # Skip if no markdown files found + [[ -e "$md_file" ]] || continue + + base_name=$(basename "$md_file") + html_file="$POSTS_DEPLOY_DIR/${base_name%.md}.html" + local_html_file="$MD_DIR/${base_name%.md}.html" + + log_debug "Processing $base_name" + + # Check if HTML file doesn't exist or markdown file is newer + if [[ ! -f "$html_file" ]] || [[ "$md_file" -nt "$html_file" ]]; then + echo "Converting $base_name to HTML..." + if ! node "$SRC_DIR/js/md-to-html.js" "$md_file" "$html_file"; then + echo "Error: Failed to convert $base_name to HTML" + exit 1 + fi + cp "$html_file" "$local_html_file" + ((CONVERTED_COUNT++)) + fi +done + +echo "Converted $CONVERTED_COUNT new or modified files" + +# Update summaries in index.html +echo "Updating blog post summaries in index.html..." +if ! npm run update-summaries; then + echo "Error: Failed to update summaries" + exit 1 +fi + +# Generate RSS feed +echo "Generating RSS feed..." +if ! node "$SRC_DIR/js/generate-rss.js"; then + echo "Error: Failed to generate RSS feed" + exit 1 +fi + +# Copy necessary files to deploy directory +echo "Copying files to deploy directory..." +cp index.html "$DEPLOY_DIR/" +cp -r dist/* "$DEPLOY_DIR/dist/" + +# If --serve flag is provided, start the server +if [ "$SERVE" = true ]; then + # Find available port if specified port is in use + FINAL_PORT=$(find_available_port "$PORT") + + echo "Starting local server on port $FINAL_PORT..." + echo "Visit http://localhost:$FINAL_PORT to view your site" + echo "Press Ctrl+C to stop the server" + + # Copy deploy files to root for local development + cp -r "$DEPLOY_DIR"/* . + + # Ensure live-server exists + if [ ! -f "./node_modules/.bin/live-server" ]; then + echo "Error: live-server not found. Please run 'npm install' first." + exit 1 + fi + + # Start live-server with specific options + ./node_modules/.bin/live-server \ + --port="$FINAL_PORT" \ + --no-browser \ + --watch="*.html,*.css,content/**/*.html" \ + --wait=50 \ + --quiet \ + --ignore=node_modules \ + . + + # Keep script running until Ctrl+C + wait +fi diff --git a/content/posts/2025-04-04-one-year-of-craftering.html b/content/posts/2025-04-04-one-year-of-craftering.html index e37afd4..92d03b7 100644 --- a/content/posts/2025-04-04-one-year-of-craftering.html +++ b/content/posts/2025-04-04-one-year-of-craftering.html @@ -1,149 +1,148 @@ - - - - - - - - - - "One Year of Craftering: Building Connections in the System Crafters Community" - Glenn Thompson - - - - - - - - -
-
-
-
-

"One Year of Craftering: Building Connections in the System Crafters Community"

-
- - - 3 min read - - By Glenn Thompson -
- -
- [communitywebringsystemcraftersreflection] -
-
- -
-

Next Thursday, 03-APR-2025, marks the first anniversary of the Craftering webring, a vibrant community initiative started by shom that connects personal websites and blogs within the System Crafters community. As one of the members of this webring, I've had the privilege of being part of this journey from its early days.

-

My First Pull Request

-

Joining Craftering was actually my first experience with the pull request workflow on Codeberg. As someone new to contributing to open source projects, I was initially intimidated by the process. However, shom took the time to walk me through each step, providing clear guidance and encouragement. This hands-on experience with git and PR workflows proved invaluable, making the technical aspects of contribution much less daunting.

-

As shom recently reflected, this kind of supportive onboarding was an intentional part of Craftering's design - creating opportunities for community members to learn and grow together through practical experience.

-

The Power of Connected Personal Spaces

-

The Craftering webring represents more than just a collection of links - it's a testament to the enduring value of personal websites and the importance of community-driven content. In an era dominated by social media platforms and algorithmic feeds, webrings offer a refreshing return to the web's roots: direct connections between individually crafted spaces.

-

Community Impact and Discoveries

-

Being part of the Craftering webring has enriched my own blogging experience in several ways:

-
    -
  1. Diverse Perspectives: Through the webring, I've discovered fellow creators sharing their experiences with everything from Emacs configurations to system design principles.

    -
  2. -
  3. Technical Cross-Pollination: Reading other members' blogs has introduced me to new tools and approaches. For instance, my recent transition to a custom static site generator was partly inspired by discussions and posts from the community.

    -
  4. -
  5. Consistent Motivation: Knowing that my blog is part of an interconnected community has encouraged more regular writing and sharing.

    -
  6. -
-

Technical Integration and RSS

-

One of the strengths of the Craftering webring is its embrace of RSS feeds, making it easy to follow updates from all community members. The webring's OPML file allows for quick subscription to all member feeds, creating a genuine sense of connection through content updates.

-

Looking Forward

-

As we celebrate this first year, it's exciting to see how the webring has grown and evolved. From the initial members to our current diverse group, each addition has brought new perspectives and valuable contributions to our community.

-

The success of Craftering demonstrates that the spirit of the early web - decentralized, personal, and community-driven - is very much alive. It shows that there's still tremendous value in maintaining personal spaces on the web, connected through shared interests and mutual respect for individual expression.

-

Join the Ring

-

If you maintain a personal website and are interested in connecting with like-minded individuals, consider joining the Craftering webring. The process is straightforward, and you'll be joining a supportive community of creators and thinkers who value personal expression and technical craftsmanship.

-

Here's to another year of crafting, sharing, and building connections in our corner of the web!

- -
-
-
-
- - + + + + + + + + + + Blog Post - Glenn Thompson + + + + + + + + +
+
+
+
+

Blog Post

+
+ + + 3 min read + + By Glenn Thompson +
+ +
+ +
+
+

title: "One Year of Craftering: Building Connections in the System Crafters Community"
date: 2025-04-02
tags: [community, webring, systemcrafters, reflection]

+

Next Thursday, 03-APR-2025, marks the first anniversary of the Craftering webring, a vibrant community initiative started by shom that connects personal websites and blogs within the System Crafters community. As one of the members of this webring, I've had the privilege of being part of this journey from its early days.

+

My First Pull Request

+

Joining Craftering was actually my first experience with the pull request workflow on Codeberg. As someone new to contributing to open source projects, I was initially intimidated by the process. However, shom took the time to walk me through each step, providing clear guidance and encouragement. This hands-on experience with git and PR workflows proved invaluable, making the technical aspects of contribution much less daunting.

+

As shom recently reflected, this kind of supportive onboarding was an intentional part of Craftering's design - creating opportunities for community members to learn and grow together through practical experience.

+

The Power of Connected Personal Spaces

+

The Craftering webring represents more than just a collection of links - it's a testament to the enduring value of personal websites and the importance of community-driven content. In an era dominated by social media platforms and algorithmic feeds, webrings offer a refreshing return to the web's roots: direct connections between individually crafted spaces.

+

Community Impact and Discoveries

+

Being part of the Craftering webring has enriched my own blogging experience in several ways:

+
    +
  1. Diverse Perspectives: Through the webring, I've discovered fellow creators sharing their experiences with everything from Emacs configurations to system design principles.

    +
  2. +
  3. Technical Cross-Pollination: Reading other members' blogs has introduced me to new tools and approaches. For instance, my recent transition to a custom static site generator was partly inspired by discussions and posts from the community.

    +
  4. +
  5. Consistent Motivation: Knowing that my blog is part of an interconnected community has encouraged more regular writing and sharing.

    +
  6. +
+

Technical Integration and RSS

+

One of the strengths of the Craftering webring is its embrace of RSS feeds, making it easy to follow updates from all community members. The webring's OPML file allows for quick subscription to all member feeds, creating a genuine sense of connection through content updates.

+

Looking Forward

+

As we celebrate this first year, it's exciting to see how the webring has grown and evolved. From the initial members to our current diverse group, each addition has brought new perspectives and valuable contributions to our community.

+

The success of Craftering demonstrates that the spirit of the early web - decentralized, personal, and community-driven - is very much alive. It shows that there's still tremendous value in maintaining personal spaces on the web, connected through shared interests and mutual respect for individual expression.

+

Join the Ring

+

If you maintain a personal website and are interested in connecting with like-minded individuals, consider joining the Craftering webring. The process is straightforward, and you'll be joining a supportive community of creators and thinkers who value personal expression and technical craftsmanship.

+

Here's to another year of crafting, sharing, and building connections in our corner of the web!

+ +
+
+
+
+ + \ No newline at end of file diff --git a/content/posts/2025-09-28-dev-environment-evolution-guix-home.html b/content/posts/2025-09-28-dev-environment-evolution-guix-home.html new file mode 100644 index 0000000..d8f8b22 --- /dev/null +++ b/content/posts/2025-09-28-dev-environment-evolution-guix-home.html @@ -0,0 +1,273 @@ + + + + + + + + + + "Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow" - Glenn Thompson + + + + + + + + +
+
+
+
+

"Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow"

+
+ + + 8 min read + + By Glenn Thompson +
+ +
+ ["development""guix""guix-home""emacs""workflow""productivity""evolution"] +
+
+ +
+

Introduction

+

Six months ago, I shared a detailed look at my development environment in 2025, covering my hybrid approach with ArcoLinux, Guix package management, and Emacs-centered workflow. Since then, my setup has undergone a significant evolution driven by both choice and necessity.

+

The most significant change has been a transition to WSL2 on Windows 11 for my work environment, necessitated by corporate requirements. Rather than seeing this as a limitation, I've embraced it as an opportunity to refine my development approach, adopting Guix Home for complete environment management and building a custom Emacs installation from the master branch.

+

This evolution has taught me valuable lessons about adaptability and the power of declarative configuration in maintaining consistency across different underlying systems.

+

The Guix Home Revolution

+

From Hybrid to Unified

+

In March, I described my hybrid approach using both pacman/AUR and Guix for different aspects of my system. While this worked well, I found myself constantly managing the boundary between system and user packages, dealing with occasional conflicts, and maintaining separate configuration files.

+

Guix Home changed everything. Now I can declaratively manage:

+
    +
  • All my development tools and applications
  • +
  • Shell configuration and environment variables
  • +
  • Dotfiles and configuration files
  • +
  • Services and background processes
  • +
  • Desktop environment customizations
  • +
+

Current Guix Home Configuration

+

My home-configuration.scm has become the single source of truth for my development environment, particularly focused on Scheme/Guile development:

+
;; Guix Home configuration for Glenn's Scheme development environment
+
+(use-modules (gnu home)
+             (gnu packages)
+             (gnu services)
+             (gnu home services)
+             (gnu home services shells)
+             (gnu home services guix)
+             (gnu home services mcron)
+             (guix gexp))
+
+(home-environment
+  ;; Packages to install in the home environment
+  (packages (specifications->packages 
+             '(;; System essentials
+               "glibc-locales"
+               
+               ;; Scheme/Guile development environment
+               "guile-next"        ; Latest Guile development version
+               "guile-hoot"        ; Scheme to WebAssembly compiler
+               "guile-goblins"     ; Distributed programming environment
+               "guile-lib"         ; Useful Guile libraries
+               "guile-reader"      ; Reader extensions for Guile
+               "guile-json"        ; JSON support for Guile
+               
+               ;; Development tools  
+               ;; Note: Using custom-built Emacs 31.0.50 installation
+               "git"               ; Version control
+               "make"              ; Build system
+               "gcc-toolchain"     ; C compiler and tools
+               "pkg-config"        ; Package configuration
+               "texinfo"           ; Documentation system
+               "rlwrap")))         ; Readline wrapper for better REPL experience
+
+  ;; Services for the home environment
+  (services
+   (list
+    ;; Set up environment variables for Scheme development
+    (simple-service 'scheme-dev-env-vars
+                    home-environment-variables-service-type
+                    '(("EDITOR" . "emacs")
+                      ("GUILE_LOAD_PATH" . "$HOME/.guix-home/profile/share/guile/site/3.0:$GUILE_LOAD_PATH")
+                      ("GUILE_LOAD_COMPILED_PATH" . "$HOME/.guix-home/profile/lib/guile/3.0/site-ccache:$GUILE_LOAD_COMPILED_PATH")
+                      ("GUIX_LOCPATH" . "$HOME/.guix-home/profile/lib/locale")
+                      ("GUILE_AUTO_COMPILE" . "1")
+                      ("GUILE_WARN_DEPRECATED" . "detailed")))
+
+    ;; Add a simple mcron job for keeping system updated
+    (simple-service 'update-reminder
+                    home-mcron-service-type
+                    (list #~(job "0 12 * * 0"  ; Every Sunday at noon
+                                "echo 'Consider running: guix pull && guix home reconfigure ~/.config/guix/home-configuration.scm'"))))))
+
+

Benefits Realized

+

The transition to Guix Home has delivered on its promises:

+

Complete Reproducibility: I can now recreate my entire user environment on any machine with a single command: guix home reconfigure home-configuration.scm

+

Atomic Updates: Changes to my environment are atomic - either they work completely or roll back cleanly. No more broken states from partial updates.

+

Version Control Everything: My entire environment configuration lives in Git, with meaningful commit messages tracking every change to my setup.

+

Effortless Rollbacks: When an update breaks something, guix home roll-back instantly restores the previous working state.

+

Dependency Isolation: Each application gets exactly the dependencies it needs, eliminating conflicts between different tools requiring different library versions.

+

Enhanced Emacs Workflow

+

Custom Emacs Build from Master

+

One of the most significant changes in my setup has been building Emacs from the master branch rather than relying on distribution packages. This decision was driven by several factors:

+
    +
  • Latest Features: Access to cutting-edge features and improvements before they reach stable releases
  • +
  • WSL2 Optimization: Better integration with the WSL2 environment through custom compilation flags
  • +
  • Performance Tuning: Ability to optimize the build for my specific use case and hardware
  • +
+

Building Emacs 31.0.50 from source on WSL2 Ubuntu has given me a more responsive and feature-rich editing environment, particularly for Scheme development where the latest improvements in language support make a noticeable difference.

+

Configuration Management Evolution

+

While I was already using Emacs extensively in March, my configuration approach has matured significantly. I've moved from a monolithic configuration to a modular, feature-based system that's easier to maintain and debug.

+

New Emacs Enhancements

+

Improved LSP Integration: My language server setup now provides more consistent and reliable code intelligence across all my projects.

+

Enhanced Org Mode Workflow: I've integrated Org mode more deeply into my daily workflow for:

+
    +
  • Project planning and tracking
  • +
  • Meeting notes and documentation
  • +
  • Time tracking and productivity analysis
  • +
  • Knowledge management and linking
  • +
+

Better Terminal Integration: Using vterm and multi-vterm, I now have seamless terminal integration within Emacs, reducing context switching.

+

Refined Completion System: My completion setup with Vertico, Consult, and Marginalia has been fine-tuned for faster, more intuitive navigation.

+

Development Workflow Improvements

+

Project Management: Using projectile with enhanced project templates and automated setup scripts.

+

Code Quality: Integrated formatting, linting, and testing directly into my editing workflow with immediate feedback.

+

Documentation: Streamlined documentation generation and maintenance using Org mode's export capabilities.

+

Workflow Integration Benefits

+

Seamless Environment Switching

+

With Guix Home managing my entire environment, switching between different project contexts has become effortless. Each project can specify its exact dependencies, and Guix ensures they're available without affecting other projects.

+

Consistent Across Machines

+

Whether I'm working on my desktop, laptop, or a remote server, my environment is identical. This consistency has eliminated the "works on my machine" problem entirely.

+

Simplified Onboarding

+

Setting up a new development machine now takes minutes instead of hours. Clone my configuration repository, run guix home reconfigure, and everything is ready.

+

Challenges and Solutions

+

Learning Curve

+

Challenge: Guix Home's declarative approach required rethinking how I manage my environment.

+

Solution: Incremental migration, starting with simple configurations and gradually adding complexity as I became more comfortable with the system.

+

Documentation Gaps

+

Challenge: Guix Home is relatively new, with fewer examples and tutorials compared to traditional dotfile management.

+

Solution: Active participation in the Guix community, reading source code, and documenting my own discoveries.

+

Integration Complexity

+

Challenge: Some applications required custom integration work to play nicely with Guix Home.

+

Solution: Creating custom service definitions and contributing them back to the community when possible.

+

Performance and Productivity Impact

+

The move to Guix Home has had measurable impacts on my productivity:

+
    +
  • Reduced Setup Time: New project environments spin up in seconds
  • +
  • Fewer Context Switches: Everything I need is consistently available
  • +
  • Less Debugging: Reproducible environments mean fewer environment-related issues
  • +
  • Improved Focus: Less time managing tools means more time creating
  • +
+

Future Directions

+

Looking ahead, I'm exploring:

+

Custom Guix Channels: Creating personal channels for specialized tools and configurations not yet in the main Guix repository.

+

Advanced Service Integration: Developing more sophisticated service definitions for complex development workflows.

+

Cross-Machine Synchronization: Using Guix Home with remote development servers and cloud environments.

+

Community Contributions: Sharing useful service definitions and configurations with the broader Guix community.

+

Lessons Learned

+

Embrace Gradual Migration

+

Don't try to convert everything at once. Start with core tools and gradually expand your Guix Home configuration as you become more comfortable with the system.

+

Document Everything

+

Keep detailed notes about your configuration choices. The declarative nature of Guix Home makes it easy to forget why you made certain decisions.

+

Engage with the Community

+

The Guix community is incredibly helpful and knowledgeable. Don't hesitate to ask questions and share your experiences.

+

Version Control is Essential

+

Treat your Guix Home configuration like any other important code - use meaningful commit messages, create branches for experiments, and maintain good version control hygiene.

+

Conclusion

+

The evolution from my March setup to the current Guix Home-based environment represents more than just a tool change - it's a fundamental shift in how I think about development environment management. The move from imperative to declarative configuration has brought a level of reliability and reproducibility that has transformed my daily workflow.

+

For anyone considering similar changes, I'd recommend starting small and gradually expanding your declarative configuration. The initial learning curve is worth the long-term benefits of having a truly reproducible, version-controlled development environment.

+

The combination of Guix Home for environment management and a refined Emacs configuration has created a development setup that feels both powerful and effortless. It's a foundation I'm confident will serve me well as my projects and requirements continue to evolve.

+

What aspects of environment management do you find most challenging? Have you experimented with declarative configuration approaches? I'd love to hear about your experiences and any questions you might have about making similar transitions.

+ +
+
+
+
+ + + \ No newline at end of file diff --git a/content/posts/2025-09-28-dev-environment-evolution-guix-home.md b/content/posts/2025-09-28-dev-environment-evolution-guix-home.md new file mode 100644 index 0000000..554daf1 --- /dev/null +++ b/content/posts/2025-09-28-dev-environment-evolution-guix-home.md @@ -0,0 +1,222 @@ +--- +title: "Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow" +date: "2025-09-28 10:05" +tags: ["development", "guix", "guix-home", "emacs", "workflow", "productivity", "evolution"] +description: "Six months after my comprehensive development environment overview, I share the significant evolution to Guix Home and enhanced Emacs configurations that have transformed my daily workflow." +--- + +## Introduction + +Six months ago, I shared a detailed look at my [development environment in 2025](/content/posts/2025-03-08-my-dev-environment-2025.html), covering my hybrid approach with ArcoLinux, Guix package management, and Emacs-centered workflow. Since then, my setup has undergone a significant evolution driven by both choice and necessity. + +The most significant change has been a transition to **WSL2 on Windows 11** for my work environment, necessitated by corporate requirements. Rather than seeing this as a limitation, I've embraced it as an opportunity to refine my development approach, adopting **Guix Home** for complete environment management and building a custom Emacs installation from the master branch. + +This evolution has taught me valuable lessons about adaptability and the power of declarative configuration in maintaining consistency across different underlying systems. + +## The Guix Home Revolution + +### From Hybrid to Unified + +In March, I described my hybrid approach using both pacman/AUR and Guix for different aspects of my system. While this worked well, I found myself constantly managing the boundary between system and user packages, dealing with occasional conflicts, and maintaining separate configuration files. + +**Guix Home** changed everything. Now I can declaratively manage: + +- All my development tools and applications +- Shell configuration and environment variables +- Dotfiles and configuration files +- Services and background processes +- Desktop environment customizations + +### Current Guix Home Configuration + +My `home-configuration.scm` has become the single source of truth for my development environment, particularly focused on Scheme/Guile development: + +```scheme +;; Guix Home configuration for Glenn's Scheme development environment + +(use-modules (gnu home) + (gnu packages) + (gnu services) + (gnu home services) + (gnu home services shells) + (gnu home services guix) + (gnu home services mcron) + (guix gexp)) + +(home-environment + ;; Packages to install in the home environment + (packages (specifications->packages + '(;; System essentials + "glibc-locales" + + ;; Scheme/Guile development environment + "guile-next" ; Latest Guile development version + "guile-hoot" ; Scheme to WebAssembly compiler + "guile-goblins" ; Distributed programming environment + "guile-lib" ; Useful Guile libraries + "guile-reader" ; Reader extensions for Guile + "guile-json" ; JSON support for Guile + + ;; Development tools + ;; Note: Using custom-built Emacs 31.0.50 installation + "git" ; Version control + "make" ; Build system + "gcc-toolchain" ; C compiler and tools + "pkg-config" ; Package configuration + "texinfo" ; Documentation system + "rlwrap"))) ; Readline wrapper for better REPL experience + + ;; Services for the home environment + (services + (list + ;; Set up environment variables for Scheme development + (simple-service 'scheme-dev-env-vars + home-environment-variables-service-type + '(("EDITOR" . "emacs") + ("GUILE_LOAD_PATH" . "$HOME/.guix-home/profile/share/guile/site/3.0:$GUILE_LOAD_PATH") + ("GUILE_LOAD_COMPILED_PATH" . "$HOME/.guix-home/profile/lib/guile/3.0/site-ccache:$GUILE_LOAD_COMPILED_PATH") + ("GUIX_LOCPATH" . "$HOME/.guix-home/profile/lib/locale") + ("GUILE_AUTO_COMPILE" . "1") + ("GUILE_WARN_DEPRECATED" . "detailed"))) + + ;; Add a simple mcron job for keeping system updated + (simple-service 'update-reminder + home-mcron-service-type + (list #~(job "0 12 * * 0" ; Every Sunday at noon + "echo 'Consider running: guix pull && guix home reconfigure ~/.config/guix/home-configuration.scm'")))))) +``` + +### Benefits Realized + +The transition to Guix Home has delivered on its promises: + +**Complete Reproducibility**: I can now recreate my entire user environment on any machine with a single command: `guix home reconfigure home-configuration.scm` + +**Atomic Updates**: Changes to my environment are atomic - either they work completely or roll back cleanly. No more broken states from partial updates. + +**Version Control Everything**: My entire environment configuration lives in Git, with meaningful commit messages tracking every change to my setup. + +**Effortless Rollbacks**: When an update breaks something, `guix home roll-back` instantly restores the previous working state. + +**Dependency Isolation**: Each application gets exactly the dependencies it needs, eliminating conflicts between different tools requiring different library versions. + +## Enhanced Emacs Workflow + +### Custom Emacs Build from Master + +One of the most significant changes in my setup has been building Emacs from the master branch rather than relying on distribution packages. This decision was driven by several factors: + +- **Latest Features**: Access to cutting-edge features and improvements before they reach stable releases +- **WSL2 Optimization**: Better integration with the WSL2 environment through custom compilation flags +- **Performance Tuning**: Ability to optimize the build for my specific use case and hardware + +Building Emacs 31.0.50 from source on WSL2 Ubuntu has given me a more responsive and feature-rich editing environment, particularly for Scheme development where the latest improvements in language support make a noticeable difference. + +### Configuration Management Evolution + +While I was already using Emacs extensively in March, my configuration approach has matured significantly. I've moved from a monolithic configuration to a modular, feature-based system that's easier to maintain and debug. + +### New Emacs Enhancements + +**Improved LSP Integration**: My language server setup now provides more consistent and reliable code intelligence across all my projects. + +**Enhanced Org Mode Workflow**: I've integrated Org mode more deeply into my daily workflow for: +- Project planning and tracking +- Meeting notes and documentation +- Time tracking and productivity analysis +- Knowledge management and linking + +**Better Terminal Integration**: Using `vterm` and `multi-vterm`, I now have seamless terminal integration within Emacs, reducing context switching. + +**Refined Completion System**: My completion setup with Vertico, Consult, and Marginalia has been fine-tuned for faster, more intuitive navigation. + +### Development Workflow Improvements + +**Project Management**: Using `projectile` with enhanced project templates and automated setup scripts. + +**Code Quality**: Integrated formatting, linting, and testing directly into my editing workflow with immediate feedback. + +**Documentation**: Streamlined documentation generation and maintenance using Org mode's export capabilities. + +## Workflow Integration Benefits + +### Seamless Environment Switching + +With Guix Home managing my entire environment, switching between different project contexts has become effortless. Each project can specify its exact dependencies, and Guix ensures they're available without affecting other projects. + +### Consistent Across Machines + +Whether I'm working on my desktop, laptop, or a remote server, my environment is identical. This consistency has eliminated the "works on my machine" problem entirely. + +### Simplified Onboarding + +Setting up a new development machine now takes minutes instead of hours. Clone my configuration repository, run `guix home reconfigure`, and everything is ready. + +## Challenges and Solutions + +### Learning Curve + +**Challenge**: Guix Home's declarative approach required rethinking how I manage my environment. + +**Solution**: Incremental migration, starting with simple configurations and gradually adding complexity as I became more comfortable with the system. + +### Documentation Gaps + +**Challenge**: Guix Home is relatively new, with fewer examples and tutorials compared to traditional dotfile management. + +**Solution**: Active participation in the Guix community, reading source code, and documenting my own discoveries. + +### Integration Complexity + +**Challenge**: Some applications required custom integration work to play nicely with Guix Home. + +**Solution**: Creating custom service definitions and contributing them back to the community when possible. + +## Performance and Productivity Impact + +The move to Guix Home has had measurable impacts on my productivity: + +- **Reduced Setup Time**: New project environments spin up in seconds +- **Fewer Context Switches**: Everything I need is consistently available +- **Less Debugging**: Reproducible environments mean fewer environment-related issues +- **Improved Focus**: Less time managing tools means more time creating + +## Future Directions + +Looking ahead, I'm exploring: + +**Custom Guix Channels**: Creating personal channels for specialized tools and configurations not yet in the main Guix repository. + +**Advanced Service Integration**: Developing more sophisticated service definitions for complex development workflows. + +**Cross-Machine Synchronization**: Using Guix Home with remote development servers and cloud environments. + +**Community Contributions**: Sharing useful service definitions and configurations with the broader Guix community. + +## Lessons Learned + +### Embrace Gradual Migration + +Don't try to convert everything at once. Start with core tools and gradually expand your Guix Home configuration as you become more comfortable with the system. + +### Document Everything + +Keep detailed notes about your configuration choices. The declarative nature of Guix Home makes it easy to forget why you made certain decisions. + +### Engage with the Community + +The Guix community is incredibly helpful and knowledgeable. Don't hesitate to ask questions and share your experiences. + +### Version Control is Essential + +Treat your Guix Home configuration like any other important code - use meaningful commit messages, create branches for experiments, and maintain good version control hygiene. + +## Conclusion + +The evolution from my March setup to the current Guix Home-based environment represents more than just a tool change - it's a fundamental shift in how I think about development environment management. The move from imperative to declarative configuration has brought a level of reliability and reproducibility that has transformed my daily workflow. + +For anyone considering similar changes, I'd recommend starting small and gradually expanding your declarative configuration. The initial learning curve is worth the long-term benefits of having a truly reproducible, version-controlled development environment. + +The combination of Guix Home for environment management and a refined Emacs configuration has created a development setup that feels both powerful and effortless. It's a foundation I'm confident will serve me well as my projects and requirements continue to evolve. + +What aspects of environment management do you find most challenging? Have you experimented with declarative configuration approaches? I'd love to hear about your experiences and any questions you might have about making similar transitions. diff --git a/deploy.sh b/deploy.sh index 02bc2b7..e0b76f2 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,117 +1,117 @@ -#!/bin/bash - -# Function to show usage -show_usage() { - echo "Usage: $0 [--ftp]" - echo "Options:" - echo " --ftp Upload to FTP server (requires .env.gpg file with encrypted credentials)" - exit 1 -} - -# Function to decrypt credentials -decrypt_credentials() { - if [ ! -f ".env.gpg" ]; then - echo "Error: .env.gpg file not found!" - exit 1 - fi - - # Create a temporary file for decrypted credentials - TEMP_ENV=$(mktemp) - - # Decrypt the credentials - if ! gpg --quiet --decrypt .env.gpg > "$TEMP_ENV"; then - echo "Error: Failed to decrypt credentials!" - rm "$TEMP_ENV" - exit 1 - fi - - # Source the decrypted credentials - source "$TEMP_ENV" - - # Securely remove the temporary file - rm "$TEMP_ENV" -} - -# Parse command line arguments -USE_FTP=false -while [[ "$#" -gt 0 ]]; do - case $1 in - --ftp) USE_FTP=true ;; - -h|--help) show_usage ;; - *) echo "Unknown parameter: $1"; show_usage ;; - esac - shift -done - -# Ensure deploy directory structure exists -mkdir -p deploy/content/posts - -# Temporarily save the posts -if [ -d "deploy/content/posts" ]; then - mkdir -p .tmp_posts - mv deploy/content/posts/* .tmp_posts/ 2>/dev/null || true -fi - -# Clean up deploy directory -rm -rf deploy/* - -# Restore the directory structure -mkdir -p deploy/content/posts - -# Restore the posts if they existed -if [ -d ".tmp_posts" ]; then - mv .tmp_posts/* deploy/content/posts/ 2>/dev/null || true - rm -rf .tmp_posts -fi - -# Run build process to ensure latest CSS -echo "Building CSS..." -npm run build - -echo "Generating RSS feed..." -node src/js/generate-rss.js - -# Copy necessary files -echo "Copying files..." -cp index.html deploy/ -cp favicon.svg deploy/ -cp -r dist deploy/ -cp -r src/js deploy/js -cp feed.xml deploy/ - -# Create deployment package -echo "Creating zip archive..." -cd deploy && zip -r ../website-deploy.zip ./* -cd .. - -echo "Deployment package created successfully!" -echo "Your files are ready in the 'website-deploy.zip' file" -echo "You can also find individual files in the 'deploy' directory" - -# FTP Upload if requested -if [ "$USE_FTP" = true ]; then - # Decrypt and load credentials - decrypt_credentials - - if [ -z "$FTP_HOST" ] || [ -z "$FTP_USER" ] || [ -z "$FTP_PASS" ] || [ -z "$FTP_DIR" ]; then - echo "Error: Missing FTP credentials!" - exit 1 - fi - - # Check if lftp is installed - if ! command -v lftp &> /dev/null; then - echo "Error: lftp is not installed. Please install it first." - exit 1 - fi - - echo "Starting FTP upload..." - lftp -c " - set ssl:verify-certificate no; - open -u $FTP_USER,$FTP_PASS $FTP_HOST; - lcd deploy; - cd $FTP_DIR; - mirror -R --parallel=4 --verbose; - bye" - - echo "FTP upload completed!" -fi +#!/bin/bash + +# Function to show usage +show_usage() { + echo "Usage: $0 [--ftp]" + echo "Options:" + echo " --ftp Upload to FTP server (requires .env.gpg file with encrypted credentials)" + exit 1 +} + +# Function to decrypt credentials +decrypt_credentials() { + if [ ! -f ".env.gpg" ]; then + echo "Error: .env.gpg file not found!" + exit 1 + fi + + # Create a temporary file for decrypted credentials + TEMP_ENV=$(mktemp) + + # Decrypt the credentials + if ! gpg --quiet --decrypt .env.gpg > "$TEMP_ENV"; then + echo "Error: Failed to decrypt credentials!" + rm "$TEMP_ENV" + exit 1 + fi + + # Source the decrypted credentials + source "$TEMP_ENV" + + # Securely remove the temporary file + rm "$TEMP_ENV" +} + +# Parse command line arguments +USE_FTP=false +while [[ "$#" -gt 0 ]]; do + case $1 in + --ftp) USE_FTP=true ;; + -h|--help) show_usage ;; + *) echo "Unknown parameter: $1"; show_usage ;; + esac + shift +done + +# Ensure deploy directory structure exists +mkdir -p deploy/content/posts + +# Temporarily save the posts +if [ -d "deploy/content/posts" ]; then + mkdir -p .tmp_posts + mv deploy/content/posts/* .tmp_posts/ 2>/dev/null || true +fi + +# Clean up deploy directory +rm -rf deploy/* + +# Restore the directory structure +mkdir -p deploy/content/posts + +# Restore the posts if they existed +if [ -d ".tmp_posts" ]; then + mv .tmp_posts/* deploy/content/posts/ 2>/dev/null || true + rm -rf .tmp_posts +fi + +# Run build process to ensure latest CSS +echo "Building CSS..." +npm run build + +echo "Generating RSS feed..." +node src/js/generate-rss.js + +# Copy necessary files +echo "Copying files..." +cp index.html deploy/ +cp favicon.svg deploy/ +cp -r dist deploy/ +cp -r src/js deploy/js +cp feed.xml deploy/ + +# Create deployment package +echo "Creating zip archive..." +cd deploy && zip -r ../website-deploy.zip ./* +cd .. + +echo "Deployment package created successfully!" +echo "Your files are ready in the 'website-deploy.zip' file" +echo "You can also find individual files in the 'deploy' directory" + +# FTP Upload if requested +if [ "$USE_FTP" = true ]; then + # Decrypt and load credentials + decrypt_credentials + + if [ -z "$FTP_HOST" ] || [ -z "$FTP_USER" ] || [ -z "$FTP_PASS" ] || [ -z "$FTP_DIR" ]; then + echo "Error: Missing FTP credentials!" + exit 1 + fi + + # Check if lftp is installed + if ! command -v lftp &> /dev/null; then + echo "Error: lftp is not installed. Please install it first." + exit 1 + fi + + echo "Starting FTP upload..." + lftp -c " + set ssl:verify-certificate no; + open -u $FTP_USER,$FTP_PASS $FTP_HOST; + lcd deploy; + cd $FTP_DIR; + mirror -R --parallel=4 --verbose; + bye" + + echo "FTP upload completed!" +fi diff --git a/deploy/content/posts/2025-04-04-one-year-of-craftering.html b/deploy/content/posts/2025-04-04-one-year-of-craftering.html new file mode 100644 index 0000000..92d03b7 --- /dev/null +++ b/deploy/content/posts/2025-04-04-one-year-of-craftering.html @@ -0,0 +1,148 @@ + + + + + + + + + + Blog Post - Glenn Thompson + + + + + + + + +
+
+
+
+

Blog Post

+
+ + + 3 min read + + By Glenn Thompson +
+ +
+ +
+
+

title: "One Year of Craftering: Building Connections in the System Crafters Community"
date: 2025-04-02
tags: [community, webring, systemcrafters, reflection]

+

Next Thursday, 03-APR-2025, marks the first anniversary of the Craftering webring, a vibrant community initiative started by shom that connects personal websites and blogs within the System Crafters community. As one of the members of this webring, I've had the privilege of being part of this journey from its early days.

+

My First Pull Request

+

Joining Craftering was actually my first experience with the pull request workflow on Codeberg. As someone new to contributing to open source projects, I was initially intimidated by the process. However, shom took the time to walk me through each step, providing clear guidance and encouragement. This hands-on experience with git and PR workflows proved invaluable, making the technical aspects of contribution much less daunting.

+

As shom recently reflected, this kind of supportive onboarding was an intentional part of Craftering's design - creating opportunities for community members to learn and grow together through practical experience.

+

The Power of Connected Personal Spaces

+

The Craftering webring represents more than just a collection of links - it's a testament to the enduring value of personal websites and the importance of community-driven content. In an era dominated by social media platforms and algorithmic feeds, webrings offer a refreshing return to the web's roots: direct connections between individually crafted spaces.

+

Community Impact and Discoveries

+

Being part of the Craftering webring has enriched my own blogging experience in several ways:

+
    +
  1. Diverse Perspectives: Through the webring, I've discovered fellow creators sharing their experiences with everything from Emacs configurations to system design principles.

    +
  2. +
  3. Technical Cross-Pollination: Reading other members' blogs has introduced me to new tools and approaches. For instance, my recent transition to a custom static site generator was partly inspired by discussions and posts from the community.

    +
  4. +
  5. Consistent Motivation: Knowing that my blog is part of an interconnected community has encouraged more regular writing and sharing.

    +
  6. +
+

Technical Integration and RSS

+

One of the strengths of the Craftering webring is its embrace of RSS feeds, making it easy to follow updates from all community members. The webring's OPML file allows for quick subscription to all member feeds, creating a genuine sense of connection through content updates.

+

Looking Forward

+

As we celebrate this first year, it's exciting to see how the webring has grown and evolved. From the initial members to our current diverse group, each addition has brought new perspectives and valuable contributions to our community.

+

The success of Craftering demonstrates that the spirit of the early web - decentralized, personal, and community-driven - is very much alive. It shows that there's still tremendous value in maintaining personal spaces on the web, connected through shared interests and mutual respect for individual expression.

+

Join the Ring

+

If you maintain a personal website and are interested in connecting with like-minded individuals, consider joining the Craftering webring. The process is straightforward, and you'll be joining a supportive community of creators and thinkers who value personal expression and technical craftsmanship.

+

Here's to another year of crafting, sharing, and building connections in our corner of the web!

+ +
+
+
+
+ + + \ No newline at end of file diff --git a/deploy/content/posts/2025-09-28-dev-environment-evolution-guix-home.html b/deploy/content/posts/2025-09-28-dev-environment-evolution-guix-home.html new file mode 100644 index 0000000..d8f8b22 --- /dev/null +++ b/deploy/content/posts/2025-09-28-dev-environment-evolution-guix-home.html @@ -0,0 +1,273 @@ + + + + + + + + + + "Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow" - Glenn Thompson + + + + + + + + +
+
+
+
+

"Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow"

+
+ + + 8 min read + + By Glenn Thompson +
+ +
+ ["development""guix""guix-home""emacs""workflow""productivity""evolution"] +
+
+ +
+

Introduction

+

Six months ago, I shared a detailed look at my development environment in 2025, covering my hybrid approach with ArcoLinux, Guix package management, and Emacs-centered workflow. Since then, my setup has undergone a significant evolution driven by both choice and necessity.

+

The most significant change has been a transition to WSL2 on Windows 11 for my work environment, necessitated by corporate requirements. Rather than seeing this as a limitation, I've embraced it as an opportunity to refine my development approach, adopting Guix Home for complete environment management and building a custom Emacs installation from the master branch.

+

This evolution has taught me valuable lessons about adaptability and the power of declarative configuration in maintaining consistency across different underlying systems.

+

The Guix Home Revolution

+

From Hybrid to Unified

+

In March, I described my hybrid approach using both pacman/AUR and Guix for different aspects of my system. While this worked well, I found myself constantly managing the boundary between system and user packages, dealing with occasional conflicts, and maintaining separate configuration files.

+

Guix Home changed everything. Now I can declaratively manage:

+
    +
  • All my development tools and applications
  • +
  • Shell configuration and environment variables
  • +
  • Dotfiles and configuration files
  • +
  • Services and background processes
  • +
  • Desktop environment customizations
  • +
+

Current Guix Home Configuration

+

My home-configuration.scm has become the single source of truth for my development environment, particularly focused on Scheme/Guile development:

+
;; Guix Home configuration for Glenn's Scheme development environment
+
+(use-modules (gnu home)
+             (gnu packages)
+             (gnu services)
+             (gnu home services)
+             (gnu home services shells)
+             (gnu home services guix)
+             (gnu home services mcron)
+             (guix gexp))
+
+(home-environment
+  ;; Packages to install in the home environment
+  (packages (specifications->packages 
+             '(;; System essentials
+               "glibc-locales"
+               
+               ;; Scheme/Guile development environment
+               "guile-next"        ; Latest Guile development version
+               "guile-hoot"        ; Scheme to WebAssembly compiler
+               "guile-goblins"     ; Distributed programming environment
+               "guile-lib"         ; Useful Guile libraries
+               "guile-reader"      ; Reader extensions for Guile
+               "guile-json"        ; JSON support for Guile
+               
+               ;; Development tools  
+               ;; Note: Using custom-built Emacs 31.0.50 installation
+               "git"               ; Version control
+               "make"              ; Build system
+               "gcc-toolchain"     ; C compiler and tools
+               "pkg-config"        ; Package configuration
+               "texinfo"           ; Documentation system
+               "rlwrap")))         ; Readline wrapper for better REPL experience
+
+  ;; Services for the home environment
+  (services
+   (list
+    ;; Set up environment variables for Scheme development
+    (simple-service 'scheme-dev-env-vars
+                    home-environment-variables-service-type
+                    '(("EDITOR" . "emacs")
+                      ("GUILE_LOAD_PATH" . "$HOME/.guix-home/profile/share/guile/site/3.0:$GUILE_LOAD_PATH")
+                      ("GUILE_LOAD_COMPILED_PATH" . "$HOME/.guix-home/profile/lib/guile/3.0/site-ccache:$GUILE_LOAD_COMPILED_PATH")
+                      ("GUIX_LOCPATH" . "$HOME/.guix-home/profile/lib/locale")
+                      ("GUILE_AUTO_COMPILE" . "1")
+                      ("GUILE_WARN_DEPRECATED" . "detailed")))
+
+    ;; Add a simple mcron job for keeping system updated
+    (simple-service 'update-reminder
+                    home-mcron-service-type
+                    (list #~(job "0 12 * * 0"  ; Every Sunday at noon
+                                "echo 'Consider running: guix pull && guix home reconfigure ~/.config/guix/home-configuration.scm'"))))))
+
+

Benefits Realized

+

The transition to Guix Home has delivered on its promises:

+

Complete Reproducibility: I can now recreate my entire user environment on any machine with a single command: guix home reconfigure home-configuration.scm

+

Atomic Updates: Changes to my environment are atomic - either they work completely or roll back cleanly. No more broken states from partial updates.

+

Version Control Everything: My entire environment configuration lives in Git, with meaningful commit messages tracking every change to my setup.

+

Effortless Rollbacks: When an update breaks something, guix home roll-back instantly restores the previous working state.

+

Dependency Isolation: Each application gets exactly the dependencies it needs, eliminating conflicts between different tools requiring different library versions.

+

Enhanced Emacs Workflow

+

Custom Emacs Build from Master

+

One of the most significant changes in my setup has been building Emacs from the master branch rather than relying on distribution packages. This decision was driven by several factors:

+
    +
  • Latest Features: Access to cutting-edge features and improvements before they reach stable releases
  • +
  • WSL2 Optimization: Better integration with the WSL2 environment through custom compilation flags
  • +
  • Performance Tuning: Ability to optimize the build for my specific use case and hardware
  • +
+

Building Emacs 31.0.50 from source on WSL2 Ubuntu has given me a more responsive and feature-rich editing environment, particularly for Scheme development where the latest improvements in language support make a noticeable difference.

+

Configuration Management Evolution

+

While I was already using Emacs extensively in March, my configuration approach has matured significantly. I've moved from a monolithic configuration to a modular, feature-based system that's easier to maintain and debug.

+

New Emacs Enhancements

+

Improved LSP Integration: My language server setup now provides more consistent and reliable code intelligence across all my projects.

+

Enhanced Org Mode Workflow: I've integrated Org mode more deeply into my daily workflow for:

+
    +
  • Project planning and tracking
  • +
  • Meeting notes and documentation
  • +
  • Time tracking and productivity analysis
  • +
  • Knowledge management and linking
  • +
+

Better Terminal Integration: Using vterm and multi-vterm, I now have seamless terminal integration within Emacs, reducing context switching.

+

Refined Completion System: My completion setup with Vertico, Consult, and Marginalia has been fine-tuned for faster, more intuitive navigation.

+

Development Workflow Improvements

+

Project Management: Using projectile with enhanced project templates and automated setup scripts.

+

Code Quality: Integrated formatting, linting, and testing directly into my editing workflow with immediate feedback.

+

Documentation: Streamlined documentation generation and maintenance using Org mode's export capabilities.

+

Workflow Integration Benefits

+

Seamless Environment Switching

+

With Guix Home managing my entire environment, switching between different project contexts has become effortless. Each project can specify its exact dependencies, and Guix ensures they're available without affecting other projects.

+

Consistent Across Machines

+

Whether I'm working on my desktop, laptop, or a remote server, my environment is identical. This consistency has eliminated the "works on my machine" problem entirely.

+

Simplified Onboarding

+

Setting up a new development machine now takes minutes instead of hours. Clone my configuration repository, run guix home reconfigure, and everything is ready.

+

Challenges and Solutions

+

Learning Curve

+

Challenge: Guix Home's declarative approach required rethinking how I manage my environment.

+

Solution: Incremental migration, starting with simple configurations and gradually adding complexity as I became more comfortable with the system.

+

Documentation Gaps

+

Challenge: Guix Home is relatively new, with fewer examples and tutorials compared to traditional dotfile management.

+

Solution: Active participation in the Guix community, reading source code, and documenting my own discoveries.

+

Integration Complexity

+

Challenge: Some applications required custom integration work to play nicely with Guix Home.

+

Solution: Creating custom service definitions and contributing them back to the community when possible.

+

Performance and Productivity Impact

+

The move to Guix Home has had measurable impacts on my productivity:

+
    +
  • Reduced Setup Time: New project environments spin up in seconds
  • +
  • Fewer Context Switches: Everything I need is consistently available
  • +
  • Less Debugging: Reproducible environments mean fewer environment-related issues
  • +
  • Improved Focus: Less time managing tools means more time creating
  • +
+

Future Directions

+

Looking ahead, I'm exploring:

+

Custom Guix Channels: Creating personal channels for specialized tools and configurations not yet in the main Guix repository.

+

Advanced Service Integration: Developing more sophisticated service definitions for complex development workflows.

+

Cross-Machine Synchronization: Using Guix Home with remote development servers and cloud environments.

+

Community Contributions: Sharing useful service definitions and configurations with the broader Guix community.

+

Lessons Learned

+

Embrace Gradual Migration

+

Don't try to convert everything at once. Start with core tools and gradually expand your Guix Home configuration as you become more comfortable with the system.

+

Document Everything

+

Keep detailed notes about your configuration choices. The declarative nature of Guix Home makes it easy to forget why you made certain decisions.

+

Engage with the Community

+

The Guix community is incredibly helpful and knowledgeable. Don't hesitate to ask questions and share your experiences.

+

Version Control is Essential

+

Treat your Guix Home configuration like any other important code - use meaningful commit messages, create branches for experiments, and maintain good version control hygiene.

+

Conclusion

+

The evolution from my March setup to the current Guix Home-based environment represents more than just a tool change - it's a fundamental shift in how I think about development environment management. The move from imperative to declarative configuration has brought a level of reliability and reproducibility that has transformed my daily workflow.

+

For anyone considering similar changes, I'd recommend starting small and gradually expanding your declarative configuration. The initial learning curve is worth the long-term benefits of having a truly reproducible, version-controlled development environment.

+

The combination of Guix Home for environment management and a refined Emacs configuration has created a development setup that feels both powerful and effortless. It's a foundation I'm confident will serve me well as my projects and requirements continue to evolve.

+

What aspects of environment management do you find most challenging? Have you experimented with declarative configuration approaches? I'd love to hear about your experiences and any questions you might have about making similar transitions.

+ +
+
+
+
+ + + \ No newline at end of file diff --git a/deploy/feed.xml b/deploy/feed.xml index 8f46a9a..dafaf85 100644 --- a/deploy/feed.xml +++ b/deploy/feed.xml @@ -1,996 +1,170 @@ - - - - Glenn Thompson's Blog - Personal blog about programming, technology, and other interests - https://glenneth.org - - en-us - Thu, 13 Mar 2025 04:58:18 GMT - - - Aesthetic Meets Ergonomics: My Deep Dive into the Glove80 Keyboard - As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant transformation. The hands-on tasks of yesteryears were gradually replaced by a deluge of documentations—writing, reviewing, and endless typing. This shift brought with it an unwelcome companion: discomfort in my hands and wrists, a stark reminder of the ergonomic pitfalls of conventional keyboards. It was in this context that my quest for a more ergonomic typing solution began, leading me towards the world of ALICE layout keyboards, with the [Q10 Pro by Keychron](https://www.keychron.com/products/keychron-q10-pro-alice-layout-qmk-via-wireless-custom-mechanical-keyboard) being my initial foray into this new realm. - In the quest for the ultimate ergonomic keyboard, aesthetics often take a backseat to functionality. Yet, when I first laid eyes on the Glove80, I was struck by its elegant design—a refreshing departure from the utilitarian look typical of many ergonomic keyboards. Unlike the retro vibes of the Kinesis Advantage or the DIY aesthetics of most Dactyls, the Glove80 boasts a modern, sleek appearance that complements the contemporary design language of Apple, Google, and LG devices. With its clean lines and visually appealing legends, the Glove80 not only promises ergonomic comfort but does so with style, standing out amidst a sea of competitors. -

As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant transformation. The hands-on tasks of yesteryears were gradually replaced by a deluge of documentations—writing, reviewing, and endless typing. This shift brought with it an unwelcome companion: discomfort in my hands and wrists, a stark reminder of the ergonomic pitfalls of conventional keyboards. It was in this context that my quest for a more ergonomic typing solution began, leading me towards the world of ALICE layout keyboards, with the Q10 Pro by Keychron being my initial foray into this new realm.

-

However, the relief was partial, and the shadow of wrist strain persisted, urging me to delve deeper into the ergonomic keyboard universe. My search for a truly ergonomic solution brought me to the doorstep of the Glove80 by MoErgo. Boasting a unique split design, concave key wells, and a commitment to ergonomics that seemed almost tailor-made for my situation, the Glove80 held the promise of being the oasis I was desperately seeking in the desert of my wrist discomfort.

-

This journey from an ALICE layout keyboard user to a Glove80 enthusiast was not just about finding a better typing tool; it was about embracing a healthier typing posture and redefining my interaction with computers. After a month of integrating the Glove80 into my workflow, I'm ready to share my insights and experiences. This review will explore the initial adaptation period, the impact on my wrist health, and whether the Glove80 lives up to its promise as an ergonomic game-changer.

-

First Impressions: Feel and Experience

-

Upon beginning my typing journey with the Glove80, two aspects immediately stood out. The unique choc spacing, combined with finger-specific curves for each key column, facilitated effortless access to the bottom and number rows, as well as several function keys—without the need to move my hands. This ease of reach extended to the thumb keys, thoughtfully laid out in an arc to match the natural movement of my thumbs. Additionally, the keyboard's low profile on the desk encouraged a neutral wrist position, enhancing comfort during long typing sessions. These features converged to create a typing experience that was not just comfortable but intuitively aligned with natural hand movements.

-

The Details That Matter

-
Ergonomics at Its Core
-

The hallmark of the Glove80 is its ergonomics, designed to seamlessly integrate with the user's hand movements. After fine-tuning the tenting and tilting angles—made possible by the adjustable feet on each half of the keyboard—my hands naturally fell into the optimal typing position. The thoughtfully designed key layout meant that reaching for higher rows required merely straightening or curling my fingers, aided by the keyboard's choc spacing. Each column's unique height and curve catered to the different lengths of my fingers, further minimizing strain.

-
Key Innovations
-

The Glove80 introduces keycaps with a novel MCC profile, featuring raised sides and a central cylindrical channel, made from a slick POM material. This design supports the natural sliding of fingers across keys, reducing the need to lift hands while typing. The keyboard's thumb clusters are another highlight, offering six easily accessible keys per hand. This ergonomic layout ensures that most keys are within reach without stretching, a testament to the keyboard's user-centric design.

-
Beyond Typing: Features and Flexibility
-
    -
  • Tenting and Adjustability: The Glove80's customizable tenting angles, enhanced by sturdy locking nuts, ensure a tailored typing experience that can be finely adjusted to individual preferences.
  • -
  • Comfortable Palm Rest: The integrated, detachable palm rest offers additional comfort, catering to different typing styles with ease.
  • -
  • Switch Selection: While the standard Kailh choc switches are adequate, enthusiasts might prefer customizing their keyboard with preferred switches for an optimized typing feel. I opted for the lighter Kailh Choc V1, Red Pro Linear 35gf switches.
  • -
  • Keycaps: The high-quality POM keycaps, combined with attractive and durable legends, enhance the keyboard's tactile and visual appeal.
  • -
  • Tech-Savvy Features: From its easy-to-use firmware updates via a web interface to seamless Bluetooth connectivity and impressive battery life, the Glove80 is designed for a modern, wireless world.
  • -
  • RGB Lighting: While currently limited in customization, the RGB LEDs offer aesthetic versatility to match any setup.
  • -
-

Concluding Thoughts

-

The Glove80 keyboard represents a significant leap forward in ergonomic design, marrying aesthetics with unmatched comfort and functionality. Its thoughtful features—from the infinitely adjustable tenting to the innovative keycap design—set a new standard for what ergonomic keyboards can be. While there's room for improvement in switch selection and RGB customization, these are minor quibbles in an otherwise outstanding product. For those in search of ergonomic excellence without compromising on style or performance, the Glove80 is an investment worth making, promising a typing experience that's not just comfortable but truly enjoyable.

-]]>
- https://glenneth.org/content/posts/2024-04-08-glove80-review.html - https://glenneth.org/content/posts/2024-04-08-glove80-review.html - Invalid Date - "Glenn Thompson" - ["personal", "tech", "keyboards", "glove80"] -
- - - Lessons Learned: One Year with a Custom Static Site Generator - In this post, I'll share the key lessons I've learned and insights I've gained from building and maintaining my own static site generator. While the technical details are interesting, the real value has been in the broader lessons about software development, user experience, and the balance between complexity and simplicity. - It's been just over a year since I transitioned from Haunt to my own custom static site generator for this website. What started as an experiment to gain more control over my publishing workflow has evolved into a valuable learning experience that has shaped how I approach web development projects.

-

In this post, I'll share the key lessons I've learned and insights I've gained from building and maintaining my own static site generator. While the technical details are interesting, the real value has been in the broader lessons about software development, user experience, and the balance between complexity and simplicity.

-

The Journey of Evolution

-

From Simple Beginnings

-

When I first built my static site generator, it was remarkably simple - just the essential features needed to convert my writing into a website. No extra features, no complex configurations, just the basics.

-

Today, the system has evolved considerably, but not through grand design or elaborate planning. Instead, it grew organically based on real needs and actual usage. This organic growth taught me valuable lessons about software development.

-

Lesson 1: Features Should Emerge from Usage

-

Many of the features in my static site generator emerged from actual writing and publishing needs:

-
    -
  1. The Draft System
    When I found myself working on multiple posts simultaneously, I needed a way to keep unfinished posts separate from published content. This led to the draft system, which now helps me manage my writing workflow effectively.

    -
  2. -
  3. Tag Organization
    As my collection of posts grew, I needed a way to organize related content. The tag system emerged naturally from this need, rather than being built upfront based on assumptions about how I might want to organize content.

    -
  4. -
  5. Content Validation
    After accidentally publishing a post with a malformed date and another with a duplicate title, I added validation checks. These weren't part of the initial design but came from real-world publishing mishaps.

    -
  6. -
-

Lesson 2: Simplicity Drives Performance

-

One of the most surprising lessons was how simplicity led to better performance:

-
    -
  1. Static HTML Generation
    By generating plain HTML files, the site loads quickly without any client-side processing. There's no JavaScript framework, no hydration, and no complex build process - just simple, fast HTML.

    -
  2. -
  3. Incremental Builds
    The build system only processes files that have changed. This means that even with hundreds of posts, updates are nearly instantaneous because only the necessary files are rebuilt.

    -
  4. -
  5. Minimal JavaScript
    By keeping JavaScript to a minimum and focusing on progressive enhancement, the site remains fast and accessible, even on slower connections.

    -
  6. -
-

Lesson 3: Developer Experience Matters

-

A good developer experience has proven crucial for maintaining motivation to write and publish:

-
    -
  1. Smart Port Management
    After encountering port conflicts with other services, I added automatic port detection and fallback. The system now checks if a port is in use and automatically finds the next available one, eliminating the frustration of manual port configuration.

    -
  2. -
  3. Clear Error Messages
    When something goes wrong (like a failed CSS build or HTML conversion), the system provides clear, actionable error messages. This immediate feedback helps quickly identify and fix issues during the development process.

    -
  4. -
  5. Automated Validation
    The build system validates the environment before starting, checking for required directories and dependencies. These checks catch common setup issues early, making the development process smoother.

    -
  6. -
-

Lesson 4: Content Drives Development

-

Perhaps the most important lesson has been letting content needs drive development:

-
    -
  1. Markdown Features
    I only added support for additional Markdown features (like tables and task lists) when I actually needed them in my writing. This prevented feature bloat and kept the system focused.

    -
  2. -
  3. RSS Feed
    The RSS feed wasn't part of the initial design but was added when the content volume grew enough to warrant it. This is a pattern I've seen repeatedly - features are most valuable when they solve real, existing needs.

    -
  4. -
  5. Summary Generation
    The way post summaries are generated has evolved based on the actual content I write. Initially, it was a simple character count, but it now intelligently extracts meaningful previews based on content structure.

    -
  6. -
-

Looking Forward

-

This project has taught me that the best software often evolves gradually in response to real needs rather than being built all at once from a grand design. It's a lesson that applies well beyond static site generators - it's about building software that serves actual needs rather than imagined ones.

-

Just today, while writing this post, I encountered and solved several development workflow issues. Instead of being frustrated by these challenges, I saw them as opportunities to improve the system. The resulting changes - like automatic port detection and better error handling - weren't part of any grand plan. They emerged naturally from real usage and made the system better in practical, meaningful ways.

-

The system isn't perfect, and it probably never will be. But it's continuously improving in ways that matter for my writing and publishing workflow. That, I've learned, is far more valuable than technical perfection.

-

If you're considering building your own tools, remember:

-
    -
  1. Start simple and let features emerge from actual usage
  2. -
  3. Focus on the experience - both for users and developers
  4. -
  5. Let real needs guide development
  6. -
  7. Embrace incremental improvements
  8. -
  9. Value simplicity - it often leads to better performance and maintainability
  10. -
  11. Use real-world problems as opportunities for improvement
  12. -
-

These lessons have influenced not just how I approach this project, but how I think about software development in general. Sometimes, the best insights come from the simplest projects - and often, they come right in the middle of writing about them.

-

Looking Back and Forward

-

Reflecting on this journey, the most valuable insight has been understanding that great software evolves naturally from real needs. Every feature in my static site generator—from the draft system to the validation checks—emerged from actual usage rather than upfront planning.

-

This experience has fundamentally changed how I approach software development. Instead of trying to build the perfect system from the start, I've learned to:

-
    -
  1. Start with the simplest solution that works
  2. -
  3. Let real usage guide feature development
  4. -
  5. Focus on maintainability over complexity
  6. -
  7. Prioritize the developer experience
  8. -
  9. Keep performance in mind at every step
  10. -
-

These principles have not only made my static site generator better but have also influenced how I approach every new project. Sometimes the best insights come from the simplest projects, and often they come right in the middle of writing about them.

-]]>
- https://glenneth.org/content/posts/2025-03-12-lessons-learned-custom-ssg.html - https://glenneth.org/content/posts/2025-03-12-lessons-learned-custom-ssg.html - Thu, 13 Mar 2025 00:00:00 GMT - Glenn Thompson - [web, development, javascript, static-site, lessons] -
- - - My Development Environment in 2025: From Editor to Deployment - A comprehensive look at my current development setup in 2025, covering everything from my GNU Guix system foundation to editor configurations, terminal tools, and deployment processes. - Introduction -

The tools we use shape how we work. Over the years, my development environment has evolved alongside my technical journey through different programming languages, paradigms, and projects. This post offers a snapshot of my current setup in early 2025, detailing the choices I've made and why they work for me.

-

System Foundation: ArcoLinux with GNU Guix

-

My journey to GNU Guix began through my exploration of Scheme programming, as I detailed in my GNU Guix Journey post. While I initially experimented with Guix System, I've settled on a hybrid approach: running Guix as a package manager on top of ArcoLinux (an Arch-based distribution).

-

Current Configuration Approach

-

I manage my development environment using a combination of Arch's pacman, AUR, and Guix's declarative package management. My Guix configuration lives in a Git repository, allowing me to:

-
    -
  • Track changes to my development environment over time
  • -
  • Reproduce my development setup on new hardware
  • -
  • Roll back to previous package states when needed
  • -
  • Share configuration snippets with the community
  • -
-

Key Packages and Tools

-

I maintain a hybrid package approach:

-

System packages (via pacman/AUR):

-
    -
  • Base system utilities and desktop environment
  • -
  • Graphics drivers and hardware support
  • -
  • Some GUI applications
  • -
-

Development tools (via Guix):

-
;; My primary development tools managed by Guix
-(specifications->manifest
- '("emacs" "git" "openssh" "ripgrep" "fd" "exa" "bat"
-   "guile" "node" "python" "gcc-toolchain" "make"
-   "nss-certs" "glibc-locales"))
-
-

This hybrid approach gives me the best of both worlds: Arch's extensive package repository and up-to-date system packages, combined with Guix's reproducible development environments.

-

Reproducibility Benefits

-

The reproducibility of Guix for development environments has been invaluable. I can:

-
    -
  • Spin up development environments with precise dependencies
  • -
  • Ensure consistent behavior across machines
  • -
  • Isolate project-specific dependencies using Guix environments
  • -
  • Share exact environment specifications with collaborators
  • -
-

Challenges and Solutions

-

Working with this hybrid approach isn't without challenges:

-
    -
  • Challenge: Keeping Guix packages in sync with system libraries
    Solution: Careful management of library paths and containerization when needed

    -
  • -
  • Challenge: Learning curve for Guix's declarative configuration
    Solution: Incremental adoption and community resources

    -
  • -
  • Challenge: Occasional conflicts between package managers
    Solution: Clear separation of responsibilities (system vs. development tools)

    -
  • -
-

Editor Environment: Emacs

-

After experimenting with various editors, I've settled on Emacs as my primary development environment. Its extensibility and Scheme-based configuration language (Emacs Lisp) align well with my interests.

-

Configuration Approach

-

I use a literate configuration with Org mode, which allows me to:

-
    -
  • Document my configuration choices
  • -
  • Organize settings by purpose rather than file
  • -
  • Selectively load components based on context
  • -
  • Share readable documentation with others
  • -
-

Key Extensions

-

My most valuable Emacs extensions include:

-
    -
  • Magit: Git interface that has transformed my version control workflow
  • -
  • LSP Mode: Language server integration for intelligent code assistance
  • -
  • Org Mode: For notes, task management, and literate programming
  • -
  • Projectile: Project navigation and management
  • -
  • Company: Completion framework
  • -
  • Consult/Vertico/Marginalia: Modern completion UI
  • -
  • Tree-sitter: Improved syntax highlighting and structural editing
  • -
-

Language-Specific Setups

-

For my primary languages:

-
    -
  • Scheme/Guile: Geiser for REPL integration
  • -
  • JavaScript/TypeScript: TypeScript LSP, prettier, eslint integration
  • -
  • Python: Pyright LSP, black formatting
  • -
  • Web Development: Web mode, emmet, css-mode
  • -
-

Productivity Enhancements

-

Some productivity boosters in my setup:

-
    -
  • Custom keybindings for frequent operations
  • -
  • Snippets for common code patterns
  • -
  • Template generation for new projects
  • -
  • Integration with system notifications
  • -
-

Terminal and CLI Tools

-

While Emacs handles many tasks, I still rely heavily on terminal tools for specific workflows.

-

Shell Configuration

-

I use Zsh with a custom configuration that provides:

-
    -
  • Intuitive aliases
  • -
  • Helpful prompts with Git integration
  • -
  • Command history management
  • -
  • Directory navigation shortcuts
  • -
-

Custom Scripts and Utilities

-

I've developed several custom scripts to streamline repetitive tasks:

-
    -
  • Project initialization templates
  • -
  • Deployment automation
  • -
  • System maintenance routines
  • -
  • Content management for this blog
  • -
-

Task Automation

-

For task automation, I use a combination of:

-
    -
  • Shell scripts for simple operations
  • -
  • Guile scripts for more complex logic
  • -
  • Make for build processes
  • -
  • Cron for scheduled tasks
  • -
-

Version Control Workflow

-

My Git workflow relies on:

-
    -
  • Branch-per-feature approach
  • -
  • Interactive rebasing for clean history
  • -
  • Commit message templates
  • -
  • Hooks for quality checks
  • -
-

Web Development Stack

-

As the creator of this website, my web development setup has been refined through experience.

-

Local Development Server

-

For local development, I use:

-
    -
  • Live-server for static sites
  • -
  • Custom Node.js servers for API development
  • -
  • Docker containers for complex dependencies
  • -
-

Build Tools and Processes

-

My build process typically involves:

-
    -
  • Tailwind CSS for styling
  • -
  • Minimal JavaScript bundling
  • -
  • Custom static site generation (as detailed in my previous post)
  • -
  • Automated optimization steps
  • -
-

Testing Approach

-

For testing, I employ:

-
    -
  • Jest for JavaScript unit tests
  • -
  • Cypress for end-to-end testing
  • -
  • Manual testing across devices and browsers
  • -
  • Accessibility validation tools
  • -
-

Browser Tools and Extensions

-

Essential browser tools include:

-
    -
  • Firefox Developer Edition as my primary browser
  • -
  • Chrome for cross-browser testing
  • -
  • DevTools for performance analysis
  • -
  • React and Redux DevTools
  • -
  • Accessibility checkers
  • -
-

Deployment Pipeline

-

My approach to deployment emphasizes security and reliability.

-

Secure Deployment Process

-

As you might have noticed from my .env.gpg file, I take security seriously:

-
    -
  • Credentials stored in GPG-encrypted files
  • -
  • Separate development and production configurations
  • -
  • Principle of least privilege for service accounts
  • -
  • Regular security audits
  • -
-

Automation Scripts

-

My deployment is automated through:

-
    -
  • Custom shell scripts for build and deploy
  • -
  • Validation steps before deployment
  • -
  • Rollback capabilities
  • -
  • Notification systems for success/failure
  • -
-

CI/CD Considerations

-

While not using a formal CI/CD pipeline for this personal site, I follow similar principles:

-
    -
  • Pre-commit checks for code quality
  • -
  • Automated testing before deployment
  • -
  • Consistent build environments
  • -
  • Deployment approval steps
  • -
-

Monitoring and Analytics

-

For site monitoring, I use:

-
    -
  • Simple analytics for privacy-respecting visitor tracking
  • -
  • Uptime monitoring
  • -
  • Performance metrics collection
  • -
  • Error logging and alerting
  • -
-

Future Improvements

-

My environment continues to evolve. Areas I'm exploring include:

-
    -
  • Further integration between Emacs and system tools
  • -
  • More comprehensive test automation
  • -
  • Expanded use of Guix channels for package management
  • -
  • Improved mobile development workflow
  • -
-

Conclusion

-

A development environment is deeply personal, reflecting both technical needs and individual preferences. Mine has evolved through years of experimentation, learning, and refinement.

-

The most important lesson I've learned is that tools should serve your workflow, not dictate it. Be willing to experiment, but also recognize when a tool is working well enough that further optimization yields diminishing returns.

-

I hope sharing my setup provides some inspiration for your own environment. I'd love to hear about your setup and what tools have made the biggest difference in your workflow.

-

What aspects of your development environment have you found most valuable? Are there tools or approaches you think I should consider? Let me know!

-]]>
- https://glenneth.org/content/posts/2025-03-08-my-dev-environment-2025.html - https://glenneth.org/content/posts/2025-03-08-my-dev-environment-2025.html - Sat, 08 Mar 2025 00:00:00 GMT - Glenn Thompson - development, guix, tools, workflow, productivity, web -
- - - From Hugo to Haunt to Custom: My Journey in Static Site Generation - A reflection on my evolving journey through static site generators - from Hugo to Haunt, and finally to building my own custom solution, highlighting the valuable lessons learned along the way. - My journey with static site generators has been one of continuous learning and evolution. It started with Hugo, transitioned through Haunt, and has now led me to build my own custom solution. Each step of this journey has taught me valuable lessons about web development, programming languages, and the importance of understanding the tools we use.

-

The Hugo Beginning

-

Like many "bloggers", I started with Hugo, a popular static site generator known for its speed and extensive theme ecosystem. Hugo served its purpose well, providing a robust platform for my blog with ready-made themes and a strong community.

-

The Transition to Haunt

-

My journey took an interesting turn when I joined the System Crafters Community. Through David Wilson's excellent course, Hands-On Guile Scheme for Beginners, I was introduced to the world of Scheme programming. This led me to adopt GNU Guix as my operating system, which naturally led me to Haunt, a static site generator written in Guile Scheme.

-

The transition to Haunt was motivated by several factors:

-
    -
  • Alignment with my growing interest in Scheme and functional programming
  • -
  • Integration with the GNU Guix ecosystem
  • -
  • The opportunity to write site configuration in Scheme
  • -
  • A desire for a simpler, more controllable setup
  • -
-

The Haunt Experience

-

Haunt offered a different perspective on site generation. Some highlights of my Haunt experience included:

-
    -
  • Writing site configuration in Scheme, which felt natural after learning Guile
  • -
  • Creating custom templates that matched my site's aesthetic needs
  • -
  • Learning to leverage Scheme's flexibility for site customization
  • -
  • Being part of a community that values simplicity and transparency
  • -
-

However, working with Haunt also presented challenges:

-
    -
  • Limited availability of ready-made templates
  • -
  • Need to create custom solutions for common features
  • -
  • Learning curve of Scheme for web development
  • -
-

The Move to Custom Development

-

As I became more comfortable with web development and gained a deeper understanding of static site generation, I felt ready for the next step: building my own static site generator. This decision wasn't about Haunt's limitations - it was about the desire to understand every aspect of my site's generation process and have complete control over its architecture.

-

The New Architecture

-

My custom solution combines the lessons learned from both Hugo and Haunt with modern web development practices:

-
    -
  • Modern JavaScript: Using Node.js and contemporary JavaScript tools
  • -
  • Markdown Processing: Leveraging the marked library for flexible content processing
  • -
  • Tailwind CSS: Adopting a utility-first approach to styling
  • -
  • Simple Build Process: A straightforward build script that handles all aspects of site generation
  • -
  • Development Server: Live reload functionality for immediate feedback
  • -
-

Benefits of the Custom Solution

-

Building my own solution has brought several advantages:

-
    -
  1. Complete Understanding: I now understand every aspect of my site's generation
  2. -
  3. Faster Iterations: Quick implementation of new features
  4. -
  5. Modern Development: Integration with current web development tools
  6. -
  7. Simplified Deployment: Streamlined process for updates
  8. -
  9. Better Performance: Only including features I actually need
  10. -
-

Learning Experience

-

This journey from Hugo through Haunt to a custom solution has taught me:

-
    -
  • The value of understanding different approaches to static site generation
  • -
  • The importance of choosing tools that align with your learning goals
  • -
  • How different programming paradigms (Go, Scheme, JavaScript) approach similar problems
  • -
  • The benefits of building your own tools when the learning opportunity outweighs convenience
  • -
-

Future Improvements

-

While my custom solution meets my current needs, I'm excited about potential improvements:

-
    -
  • Adding support for draft posts
  • -
  • Implementing a tag-based navigation system
  • -
  • Adding search functionality
  • -
  • Improving the build process
  • -
  • Adding image optimization
  • -
-

Conclusion

-

My journey from Hugo through Haunt to a custom solution reflects a common pattern in software development - starting with established tools, learning their principles, and eventually building your own solutions. Each step has been valuable:

-
    -
  • Hugo taught me about static site generators and their capabilities
  • -
  • Haunt introduced me to functional programming and the beauty of Scheme
  • -
  • Building my own solution has given me deep insights into web development
  • -
-

The source code for my site generator is available on GitHub. While it may not be the most feature-rich static site generator, it's perfectly tailored to my needs and represents a significant learning journey.

-

Remember, the goal of building your own tools isn't always to create something better than existing solutions - sometimes it's about the learning experience and creating something that perfectly fits your specific needs. Whether you're using Hugo, Haunt, or considering building your own solution, the most important thing is that it serves your purposes and helps you grow.

-]]>
- https://glenneth.org/content/posts/2025-01-02-from-haunt-to-custom.html - https://glenneth.org/content/posts/2025-01-02-from-haunt-to-custom.html - Thu, 02 Jan 2025 00:00:00 GMT - Glenn Thompson - web, development, javascript, static-site, haunt, guile, hugo -
- - - Beyond Theory: Building Practical Tools with Guile Scheme - Introduction - Beyond Theory: Building Practical Tools with Guile Scheme -

Introduction

-

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world problems is where the most valuable lessons emerge. This post explores what I've learned about building practical tools with Guile Scheme, sharing both successes and challenges along the way.

-

The Power of Modular Design

-

One of the most important lessons I learned was the value of modular design. Breaking down a program into focused, single-responsibility modules not only makes the code more maintainable but also helps in reasoning about the program's behavior. Here's how I structured stash:

-
(use-modules (ice-9 getopt-long)
-             (stash help)         ;; Help module
-             (stash colors)       ;; ANSI colors
-             (stash log)          ;; Logging module
-             (stash paths)        ;; Path handling module
-             (stash conflict)     ;; Conflict resolution module
-             (stash file-ops))    ;; File and symlink operations module
-
-

Each module has a specific responsibility:

-
    -
  • colors.scm: Handles ANSI color formatting for terminal output
  • -
  • conflict.scm: Manages conflict resolution when files already exist
  • -
  • file-ops.scm: Handles file system operations
  • -
  • help.scm: Provides usage information
  • -
  • log.scm: Manages logging operations
  • -
  • paths.scm: Handles path manipulation and normalization
  • -
-

Robust Path Handling

-

One of the first challenges in building a file management tool is handling paths correctly. Here's how I approached it:

-
(define (expand-home path)
-  "Expand ~ to the user's home directory."
-  (if (string-prefix? "~" path)
-      (string-append (getenv "HOME") (substring path 1))
-      path))
-
-(define (concat-path base path)
-  "Concatenate two paths, ensuring there are no double slashes."
-  (if (string-suffix? "/" base)
-      (string-append (string-drop-right base 1) "/" path)
-      (string-append base "/" path)))
-
-(define (ensure-config-path target-dir)
-  "Ensure that the target directory has .config appended, avoiding double slashes."
-  (let ((target-dir (expand-home target-dir)))
-    (if (string-suffix? "/" target-dir)
-        (set! target-dir (string-drop-right target-dir 1)))
-    (if (not (string-suffix? "/.config" target-dir))
-        (string-append target-dir "/.config")
-        target-dir)))
-
-

This approach ensures that:

-
    -
  • Home directory references (~) are properly expanded
  • -
  • Path concatenation doesn't create double slashes
  • -
  • Configuration paths are consistently structured
  • -
-

Interactive Conflict Resolution

-

Real-world tools often need to handle conflicts. I implemented an interactive conflict resolution system:

-
(define (prompt-user-for-action)
-  "Prompt the user to decide how to handle a conflict: overwrite (o), skip (s), or cancel (c)."
-  (display (color-message 
-    "A conflict was detected. Choose action - Overwrite (o), Skip (s), or Cancel (c): " 
-    yellow-text))
-  (let ((response (read-line)))
-    (cond
-      ((string-ci=? response "o") 'overwrite)
-      ((string-ci=? response "s") 'skip)
-      ((string-ci=? response "c") 'cancel)
-      (else
-       (display "Invalid input. Please try again.\n")
-       (prompt-user-for-action)))))
-
-

This provides a user-friendly interface for resolving conflicts while maintaining data safety.

-

Logging for Debugging and Auditing

-

Proper logging is crucial for debugging and auditing. I implemented a simple but effective logging system:

-
(define (current-timestamp)
-  "Return the current date and time as a formatted string."
-  (let* ((time (current-time))
-         (seconds (time-second time)))
-    (strftime "%Y-%m-%d-%H-%M-%S" (localtime seconds))))
-
-(define (log-action message)
-  "Log an action with a timestamp to the stash.log file."
-  (let ((log-port (open-file "stash.log" "a")))
-    (display (color-message 
-      (string-append "[" (current-timestamp) "] " message) 
-      green-text) log-port)
-    (newline log-port)
-    (close-port log-port)))
-
-

This logging system:

-
    -
  • Timestamps each action
  • -
  • Uses color coding for better readability
  • -
  • Maintains a persistent log file
  • -
  • Properly handles file operations
  • -
-

File Operations with Safety

-

When dealing with file system operations, safety is paramount. Here's how I handle moving directories:

-
(define (move-source-to-target source-dir target-dir)
-  "Move the entire source directory to the target directory, ensuring .config in the target path."
-  (let* ((target-dir (ensure-config-path target-dir))
-         (source-dir (expand-home source-dir))
-         (source-name (basename source-dir))
-         (target-source-dir (concat-path target-dir source-name)))
-    (if (not (file-exists? target-dir))
-        (mkdir target-dir #o755))
-    (if (file-exists? target-source-dir)
-        (handle-conflict target-source-dir source-dir delete-directory log-action)
-        (begin
-          (rename-file source-dir target-source-dir)
-          (display (format #f "Moved ~a to ~a\n" source-dir target-source-dir))
-          (log-action (format #f "Moved ~a to ~a" source-dir target-source-dir))))
-    target-source-dir))
-
-

This implementation:

-
    -
  • Ensures paths are properly formatted
  • -
  • Creates necessary directories
  • -
  • Handles conflicts gracefully
  • -
  • Logs all operations
  • -
  • Returns the new path for further operations
  • -
-

Lessons Learned

-

What Worked Well

-
    -
  1. Modular Design: Breaking the code into focused modules made it easier to maintain and test
  2. -
  3. Functional Approach: Using pure functions where possible made the code more predictable
  4. -
  5. Interactive Interface: Providing clear user prompts and colored output improved usability
  6. -
  7. Robust Logging: Detailed logging helped with debugging and understanding program flow
  8. -
-

Challenges Faced

-
    -
  1. Path Handling: Dealing with different path formats and edge cases required careful attention
  2. -
  3. Error States: Managing various error conditions while keeping the code clean
  4. -
  5. User Interface: Balancing between automation and user control
  6. -
  7. Documentation: Writing clear documentation that helps users understand the tool
  8. -
-

Moving Forward

-

Building stash has taught me that while functional programming principles are valuable, pragmatism is equally important. The key is finding the right balance between elegant functional code and practical solutions.

-

Resources

-
    -
  1. Guile Manual
  2. -
  3. My Previous Scheme Journey Post
  4. -
  5. System Crafters Community
  6. -
  7. Stash on Codeberg
  8. -
-

The code examples in this post are from my actual implementation of stash. Feel free to explore, use, and improve upon them!

-]]>
- https://glenneth.org/content/posts/2024-12-03-practical-scheme.html - https://glenneth.org/content/posts/2024-12-03-practical-scheme.html - Tue, 03 Dec 2024 07:00:00 GMT - Glenn Thompson - tech, guile, scheme, development, functional-programming -
- - - A Journey into Scheme - The course took me through the basics of Scheme, from simple expressions to more complex concepts like functions, recursion, and working with files. This structured learning environment gave me the confidence to start building stash. - My Journey into Scheme: Building a Simple Symlink Manager with Guile Scheme -

Introduction

-

I've spent my career as an electrical engineer, not a software developer. However, my recent journey in to GNU/Liniux required a tool for managing symlinks, and that's how I began learning Scheme—specifically Guile Scheme. I'm writing this post to share how I built stash, a utility that mimics GNU Stow's functionality, and how my learning journey was shaped by David Wilson's "Hands-On Guile Scheme for Beginners" course from System Crafters, more about this below.

-

How I Started with Scheme

-

My programming background was VERY limited, I produce documents in (La)Tex but I decided to take the plunge into learning Scheme, thanks to a course led by David Wilson from System Crafters. The course, "Hands-On Guile Scheme for Beginners", was incredibly helpful in making Scheme accessible even for someone like me, without a traditional programming background. I know (La)Tex isn't a programming language, it's typesetting. But how hard can it be? Right?

-

The course took me through the basics of Scheme, from simple expressions to more complex concepts like functions, recursion, and working with files. This structured learning environment gave me the confidence to start building stash.

-

The course was "instructor-led" with live meet-up sessions weekly. David has since made this course on-demand, and will be, if not already, available at the above link. Highly recommended if you are interested in taking your first steps with scheme.

-

Why Build Stash?

-

After completing David Wilson's course, I wanted to put my newly found Guile Scheme skills into practice with a real project. It wasn't enough just to understand the language conceptually—I needed to build something tangible that solved a problem I encountered regularly in my workflow. Writing stash gave me that opportunity. It allowed me to apply what I'd learned while also deepening my understanding of file manipulation, command-line tools, and conflict resolution—all within the Guile Scheme environment.

-

After migrating to GNU/Linux and speaking with other System Crafters Community members, I found I needed a way to manage symbolic links and organize directories. Existing tools like GNU Stow helped, but I wanted to learn how such tools are built. I decided to write my own version using Guile Scheme to enhance my understanding of the language and to have more control over the functionality.

-

The goal of stash is simple: allow users to move directories and create symlinks with conflict resolution, offering options to overwrite, back up, skip, or cancel the operation.

-

Breaking Down Stash

-

The core of stash revolves around:

-
    -
  1. Moving Directories: Using Scheme's file manipulation functions, I learned how to move directories and files around.
  2. -
  3. Creating Symlinks: I implemented functions to create symlinks to the moved directories, ensuring that the original structure remains accessible.
  4. -
  5. Conflict Resolution: One of the key features I wanted was handling conflicts when a file or symlink already exists at the target location. This required prompting the user for input and responding accordingly (backup, overwrite, skip, or cancel).
  6. -
-

Here's an excerpt of the core functionality that handles moving a source directory and creating a symlink:

-
;;; Helper function to move source to target
-(define (move-source-to-target source-dir target-dir)
-  "Move the entire source directory to the target directory."
-  (let* ((source-dir (expand-home source-dir))
-         (target-dir (expand-home target-dir))
-         (source-name (basename source-dir))
-         (target-source-dir (string-append target-dir "/" source-name)))
-    (if (file-exists? target-source-dir)
-        ;; Conflict handling here...
-        ...)
-    (rename-file source-dir target-source-dir)
-    (display (format #f "Moved ~a to ~a\n" source-dir target-source-dir))))
-
-

What I Learned

-

This project taught me a lot about not just Scheme, but programming in general:

-
    -
  • File and Directory Manipulation: Scheme's file handling functions were different from what I had experienced before, but they allowed for powerful manipulation of file systems.
  • -
  • Command-Line Utilities: Scheme isn't just a language for academic exercises; you can write real, useful command-line tools with it.
  • -
  • Problem Solving: From parsing command-line arguments to resolving conflicts with existing files, every part of the program required careful thought and consideration of edge cases.
  • -
-

Guile Scheme Support Resources

-
    -
  1. Guile Scheme Documentation
    The official documentation for Guile Scheme, which includes tutorials, references, and the Guile Manual.

    -
  2. -
  3. Guile Reference Manual
    A comprehensive manual covering core language concepts, libraries, and functions available in Guile Scheme.

    -
  4. -
  5. Scheme Wiki
    A community-maintained wiki that covers various Scheme dialects, including Guile Scheme, with tutorials, guides, and general information on Scheme programming.

    -
  6. -
  7. Guile at Schemers.org
    A site dedicated to Scheme with resources, libraries, tools, and documentation for Scheme and its implementations, including Guile.

    -
  8. -
  9. System Crafters
    Led by David Wilson, System Crafters provides tutorials and blog posts on Guile Scheme and other GNU tools.

    -
  10. -
  11. Guile Users Mailing List
    Join the Guile mailing list to ask questions and engage with the Guile Scheme community.

    -
  12. -
  13. Guile Cookbook
    An unofficial GitHub repository with practical code snippets and tips for Guile Scheme, covering various common use cases and tasks.

    -
  14. -
  15. #guile and #scheme on Libera Chat IRC
    A helpful IRC channel where you can connect with other Guile users for real-time support and advice.

    -
  16. -
  17. #systemcrafters on Libera Chat IRC
    A SUPER helpful IRC channel not only for guile and scheme, there are a huge variety of different people here. Tell them glenneth sent you.

    -
  18. -
-

Next Steps

-

I am still refining stash, especially around its conflict resolution system and the way it handles symbolic links. But it's in a usable state, and I'm excited to continue iterating on it. You can check out the code on Codeberg.

-

If you're curious about Scheme and how it can be used practically, I highly recommend checking out David Wilson's course. It's been instrumental in helping me grasp the concepts I needed to build this tool. Here's the link, again :) "Hands-On Guile Scheme for Beginners"

-]]>
- https://glenneth.org/content/posts/2024-09-24-scheme-journey.html - https://glenneth.org/content/posts/2024-09-24-scheme-journey.html - Tue, 24 Sep 2024 06:30:00 GMT - Glenn Thompson - personal, tech, guile, scheme, gnu, development -
- - - A Journey Through GNU Guix: From Installation to Returning to Arch Linux - As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey was insightful, filled with learning experiences, but ultimately led me back to the reliable shores of Arch. Here's a detailed account of my venture into GNU Guix, adding non-GNU channels, dealing with Nvidia drivers, running SwayWM, and the eventual retreat to Arch. - A Journey Through GNU Guix: From Installation to Returning to Arch Linux -

As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey was insightful, filled with learning experiences, but ultimately led me back to the reliable shores of Arch. Here's a detailed account of my venture into GNU Guix, adding non-GNU channels, dealing with Nvidia drivers, running SwayWM, and the eventual retreat to Arch.

-

Installation of GNU Guix

-

The installation process of GNU Guix was straightforward, thanks to the well-documented guide provided on their official website. Here's a quick rundown of the steps I followed:

-
    -
  1. Downloading the Installation Image: I started by downloading the latest ISO image from the GNU Guix website.
  2. -
  3. Creating a Bootable USB: Using dd, I created a bootable USB stick to install GNU Guix on my system.
  4. -
  5. Booting into the Installer: Booting from the USB was smooth, and I was greeted with the GNU Guix installer. The installer's simplicity reminded me of early days with Arch, where a minimalistic approach is preferred.
  6. -
  7. Partitioning and Setting Up File Systems: I partitioned my drive using fdisk and set up my file systems. I opted for ext4 for simplicity.
  8. -
  9. Configuring the System: Following the partition setup, I proceeded to configure my system by selecting the required packages and services. I decided to go with the Sway window manager as it's my preferred choice on Arch.
  10. -
-

System Configuration

-

During the installation process a window appears informing you that the config.scm file is located at /etc/config.scm. The first time I installed gnu guix on my work laptop I missed this message (pilot error) and I had to ask in the System Crafters IRC channel at irc.libera.chat, #systemcrafters. Come and join. It's a great place to be and the community there are an absolute treasure. Use your favourite IRC client or join through the webchat here. We would be glad to see you. Tell them glenneth sent you :).

-

My point is, I missed some vital information, so to the guix manual online it was. This can be found here. This link will take you to the dev version of the manual. Something else they don't tell you. This version has a little more detail than the standard manual, and I believe details extra features and may even be a little more up to date.

-

Adding Non-GNU Channels

-

One of the standout features of GNU Guix is the ability to add non-GNU channels to access a wider array of software packages. Here's how I did it:

-
    -
  1. Editing Channels: I edited the ~/.config/guix/channels.scm file to include non-GNU channels.
    (cons* (channel
    -        (name 'non-gnu)
    -        (url "https://example.com/non-gnu-channel.git"))
    -       %default-channels)
    -
    -
  2. -
  3. Updating Channels: Running guix pull updated my system to include packages from the non-GNU channel.
  4. -
-

Installing Nvidia Drivers

-

Being a gamer and someone who requires GPU acceleration for certain tasks, Nvidia drivers were a must. Here's the process I followed:

-
    -
  1. Adding Nvidia Channel: Added a channel that includes Nvidia drivers.
  2. -
  3. Installing Drivers: Installed the drivers using guix package -i nvidia-driver.
  4. -
  5. Configuring the System: I had to manually configure Xorg to use the Nvidia drivers, which involved editing the Xorg configuration files.
  6. -
-

Creating My Home Environment

-

To personalize my setup further, I used guix home import to create my own home environment and add packages. This allowed me to have a consistent environment across different machines. I also edited the config.scm file to include the latest Linux kernels and Nvidia drivers.

-

Additionally, I used the syncthing home-service-type in my home-configuration.scm file to install and configure Syncthing. This setup ensured my files were always in sync across devices, which is crucial for my workflow.

-

GNOME

-

All was good and I had a solid desktop environment running, even though it was gnome desktop. I had never used gnome, and I am more at home with a keyboard driven workflow. I had come from hyprland on Arch and wanted to get back to that workflow. The option I was presented with, in order to continue using wayland, pipewire etc. was SwayWM.

-

Sway

-

Installing SwayWM and it's dependencies and nice to haves was relatively straightforward. add the required packages, sway, swaybg, swayidle, swaylock, to my home-configuration.scm gile and run guix home reconfigure easy! The packages were installed and we were good to go.

-

The first issue I encountered was that sway does not run with the proprietary nvidia drivers, this was on the work laptop. I could get it to run but only after adding the --unsupported-gpu flag to exec sway. Lo and behold, we had a default sway window manager running.

-

Challenges with SwayWM and SMB Shares

-

With the system set up, I ran into a major roadblock: accessing SMB shares in a file manager while running SwayWM.

-
    -
  1. Thunar and GNOME Files: Neither Thunar nor the GNOME Files application could access SMB shares. This was crucial for my workflow as I frequently access network shares.
  2. -
  3. Troubleshooting: I tried various solutions, including installing additional packages and tweaking configurations, but nothing seemed to work.
  4. -
  5. Community Support: I reached out to the GNU Guix community for help. While they were supportive, the solutions provided didn't resolve my issues.
  6. -
-

To ensure that the problem was not hardware-related, I went out and purchased a Lenovo ThinkPad E16 Gen 1. I upgraded the RAM to 48GB and installed a Lenovo 2TB SSD to make it my personal laptop. However, even on this new setup, I faced the same issues accessing SMB shares and some networking services just wouldn't work.

-

I tried deleting the gdm login manager in my system configuration file, but after rebooting it was still showing the gnome login window. This was after reading somewhere online that sway was not on friendly terms with the gdm login manager.

-

Returning to Arch Linux

-

After several days of troubleshooting and not being able to access my SMB shares reliably, I made the difficult decision to revert to Arch Linux. The steps were:

-
    -
  1. Reinstalling Arch: I reinstalled Arch Linux using my tried-and-tested setup process.
  2. -
  3. Configuring SwayWM: Set up SwayWM and ensured all my applications were running smoothly.
  4. -
  5. Accessing SMB Shares: Accessing SMB shares was seamless, just as it was before my experiment with GNU Guix.
  6. -
-

Conclusion

-

I am still running GNU guix on the work laptop, I had to cave on my personal laptop and revert to Arch. My journey with GNU Guix was both enlightening and challenging. While I appreciate the functional package management and the philosophy behind GNU Guix, certain practical issues, like accessing SMB shares, were deal-breakers for my workflow. Arch Linux continues to be my go-to distribution, providing the flexibility and reliability I need for my daily tasks. So, at the moment I am using my personal laptop for work and still trying to figure out the issues I am having on my work laptop. But, to be honest, I prefer working on the thinkpad over working on the MSI laptop that work handed out :).

-

If you're an enthusiast looking to explore new package management paradigms, I highly recommend giving GNU Guix a try. Just be prepared for a few hiccups along the way, and always have a backup plan!

-
-

Feel free to share your thoughts and experiences with GNU Guix or any other distributions you've tried. Let's keep the conversation going!

-

Shameless plug

-

Go here to find all the ways you can engage with the SystemCrafters community. It's a great place to hang out and discuss all thing craftery. You will also notice the Craftering ring that I am a part of. Click the links and see blogs by some of the community members. Always interesting to read what other Crafters are up to.

-

Thanks for taking the time to read my blog post. It is greatly appreciated, and I hope you come back.

-

Happy Hacking!!

-]]>
- https://glenneth.org/content/posts/2024-07-26-gnu-guix-journey.html - https://glenneth.org/content/posts/2024-07-26-gnu-guix-journey.html - Fri, 26 Jul 2024 07:30:00 GMT - Glenn Thompson - personal, tech, gnu, guix, swaywm, nvidia -
- - - Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix - Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation. - Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix -

Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation.

-

Discovering Scheme with System Crafters

-

My journey began with a desire to dive deeper into programming languages and their ecosystems. I am a member of the System Crafters Community, and its founder, David Wilson, announced a short four week course as an introduction to Guile Scheme. The course, Hands-On Guile Scheme for Beginners, provided me with a robust introduction to Guile Scheme, a language that emphasizes simplicity and elegance. David's clear explanations and practical examples made learning Scheme both engaging and approachable.

-

The Move to GNU Guix

-

Inspired by the principles of Scheme, I decided to take a leap further into the open-source world by transitioning from Arch Linux to GNU Guix. The Guix community, particularly the folks in the #systemcrafters channel on irc.libera.chat, were incredibly supportive and instrumental in helping me navigate this new environment. Their guidance made the switch smooth and rewarding, reinforcing the power and flexibility of GNU Guix as a functional package manager and operating system. More about that experience in another post.

-

There are too many individuals to name here that have helped with the installation and configuration on Gnu guix to mention here. You all have been an incredible help for which I am extremely grateful. Thank you all , for enduring my ignorance, and for your patience and your help.

-

From Hugo to Haunt

-

As I settled into Guix, I faced a challenge: Hugo, the static site generator I previously used, was not available as a Guix package. This led me to explore alternatives and eventually discover Haunt, a Scheme-based static site generator that aligns perfectly with my newfound appreciation for Scheme and Guix.

-

Overcoming Challenges with Haunt

-

Transitioning to Haunt wasn't without its challenges. There are no readily available templating systems available for haunt like there are for hugo, but there are plenty of examples here. One of my own primary difficulties was creating a custom template that matched my site's aesthetic requirements and functionality needs. Initially, I struggled with configuring the theme layout and ensuring the CSS was applied correctly. Another hurdle was generating the correct URLs for posts and ensuring that summaries appeared as intended on the front page.

-

Thankfully, the Haunt manual proved to be an invaluable resource throughout this process. The comprehensive documentation provided clear guidance on using various modules, functions, and procedures. By carefully studying the examples and explanations, I was able to overcome the obstacles and achieve the desired results for my site. The manual's detailed descriptions of Haunt's inner workings were particularly helpful in understanding how to leverage the flexibility of Scheme to customize my blog.

-

Crafting My Own Template

-

Moving from Hugo to Haunt required me to create my own template and customize my site's appearance. This was an exciting opportunity to apply the skills I had learned from David's course and experiment with Scheme in a practical context.

-

Creating the Template

-

Haunt's flexibility allowed me to define my own theme layout and structure. Here's a snippet of my haunt.scm file, where I defined the theme layout and added custom footer content:

-
(use-modules (haunt asset)
-             (haunt builder blog)
-             (haunt builder atom)
-             (haunt builder assets)
-             (haunt reader commonmark)
-             (haunt site)
-             (haunt post)
-             (sxml simple)    ; For HTML generation
-             (srfi srfi-1)
-             (srfi srfi-19))  ; For date and time procedures
-
-;; Load custom templates
-(load "templates/post.scm")
-
-(define (format-date date)
-  (date->string date "~Y-~m-~d"))
-
-;; Define a function to generate the URL for a post
-(define (post-url post)
-  (string-append "/" (post-slug post) ".html"))
-
-;; Define a function to extract a summary from the post content
-(define (post-summary post)
-  (let ((content (post-sxml post)))
-    (if (null? content)
-        ""
-        (let ((first-paragraph (car content)))
-          (if (string? first-paragraph)
-              (substring first-paragraph 0 (min 200 (string-length first-paragraph)))
-              (sxml->string first-paragraph))))))
-
-;; Define the theme layout
-(define (theme-layout site title content)
-  (let ((current-year (number->string (date-year (current-date)))))
-    `(html
-      (head
-       (meta (@ (charset "utf-8")))
-       (meta (@ (name "viewport") (content "width=device-width, initial-scale=1.0, shrink-to-fit=no")))
-       (link (@ (rel "stylesheet") (href "/assets/palenight.css")))
-       (style
-        " .craftering {
-            margin: auto;
-            width: 50%;
-            text-align: center;
-        }
-        .webring-text {
-            text-align: center;
-            margin-bottom: 20px;
-            color: white;
-        }
-        .craftering a {
-            color: #dddddd;
-        }
-        .webring-text a {
-            color: #dddddd;
-        }")
-       (title ,title))
-      (body
-       (header (h1 ,(site-title site)))
-       (main ,content)
-       (footer (@ (class "bg-black bottom-0 w-100 pa3") (role "contentinfo"))
-               (div (@ (class "flex justify-between"))
-                    (div (@ (class "webring-text"))
-                         (p "I am part of the " (a (@ (href "https://systemcrafters.net") (target "_blank")) "System Crafters") " webring:"))
-                    (div (@ (class "craftering"))
-                         (a (@ (href "https://craftering.systemcrafters.net/@glenneth/previous")) "←")
-                         (a (@ (href "https://craftering.systemcrafters.net/")) "craftering")
-                         (a (@ (href "https://craftering.systemcrafters.net/@glenneth/next")) "→"))))))))
-
-;; Define the custom theme with a consistent layout for index
-(define my-theme
-  (theme #:name "My Custom Theme"
-         #:layout theme-layout
-         #:post-template post-template
-         #:collection-template
-         (lambda (site title posts prefix)
-           `(div (@ (class "content"))
-              (h2 ,title)
-              (ul
-                ,@(map (lambda (post)
-                         `(li
-                            (article
-                              (header
-                               (h3 (a (@ (href ,(post-url post))) ,(post-title post))))
-                              (p ,(format-date (post-date post)))
-                              (p ,(post-summary post))
-                              (p (a (@ (href ,(post-url post))) "Read more...")))))
-                       posts))))))
-
-;; Site configuration
-(site #:title "Just Another Personal Blog"
-      #:domain "glenneth.srht.site"
-      #:default-metadata
-      '((author . "Glenn Thompson")
-        (email  . "glenn@kirstol.org"))
-      #:readers (list commonmark-reader)
-      #:builders (list
-                  (blog #:theme my-theme)
-                  (atom-feed)
-                  (atom-feeds-by-tag)
-                  (static-directory "images")
-                  (static-directory "assets")))
-
-

Customizing the CSS

-

To give my site a personalized touch, I crafted a CSS stylesheet that matched my aesthetic preferences. Here’s an excerpt from my palenight.css file:

-
body {
-  display: flex;
-  justify-content: center;
-  padding: 10px;
-}
-
-.content, header, footer, main {
-  max-width: 90%;
-  padding: 0 5%;
-}
-
-header {
-  text-align: center;
-  margin-bottom: 20px;
-}
-
-footer {
-  text-align: center;
-  margin-top: 20px;
-}
-
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-
-li {
-  margin-bottom: 20px;
-}
-
-a {
-  text-decoration: none;
-}
-
-a:hover {
-  text-decoration: underline;
-}
-
-body {
-  background-color: #292d3e;
-  color: #d0d0d0;
-}
-
-a {
-  color: #82aaff;
-}
-
-h1, h2, h3, h4, h5, h6 {
-  color: #c792ea;
-}
-
-.content {
-  background-color: #1e1e2e;
-  padding: 20px;
-  border-radius: 5px;
-}
-
-article {
-  background-color: #282a36;
-  padding: 15px;
-  border-radius: 8px;
-  margin-bottom: 20px;
-}
-
-article header {
-  margin-bottom: 10px;
-}
-
-.date {
-  color: #6272a4;
-  font-size: 0.9em;
-}
-
-/* Additional styles for the craftering */
-.craftering {
-  margin: auto;
-  width: 50%;
-  text-align: center;
-}
-
-.webring-text {
-  text-align: center;
-  margin-bottom: 20px;
-  color: white;
-}
-
-.craftering a {
-  color: #dddddd;
-}
-
-.webring-text a {
-  color: #dddddd;
-}
-
-/* Additions for mobile device readability */
-
-meta {
-  name: viewport;
-  content: width=device-width, initial-scale=1, shrink-to-fit=no;
-}
-
-@media screen and (max-width: 767px) {
-  /* Customize styles for smaller screens */
-  .logo {
-    max-width: 200px;
-  }
-
-}
-
-

I use the doom-palenight theme in Emacs, my preferred text editor, and I wanted my site to match that aesthetic.

-

Publishing with Haunt and Hut

-

In addition to using Haunt, I adopted hut, a set of command-line tools for interacting with SourceHut, to publish my blog. This streamlined my workflow, making it easier to manage and deploy my site directly from my local environment.

-

Conclusion

-

Transitioning from Hugo to Haunt, learning Scheme, and embracing GNU Guix has been an enriching experience. It's not just about using new tools; it's about joining a community that values simplicity, transparency, and collaboration. If you're curious about Scheme or GNU Guix, I highly recommend checking out David Wilson's course on System Crafters and joining the discussions on IRC.

-

I am not a developer of any kind, and learning Scheme has opened my eyes as to how I can craft an environment that I want to work in, and not endure a working environment that the computer is forcing upon me.

-

Thank you for reading, and stay tuned for more updates on my journey!

-]]>
- https://glenneth.org/content/posts/2024-05-15-hugo-to-haunt.html - https://glenneth.org/content/posts/2024-05-15-hugo-to-haunt.html - Wed, 15 May 2024 07:30:00 GMT - Glenn Thompson - personal, tech, keyboards, glove80 -
- - - A Rollercoaster Week: From Amman to Newcastle, and back again - The Journey Begins - Two weeks ago was a whirlwind of events, taking me from the conforting embrace of Amman, Jordan to the vibrant streets of Newcastle, England. It was a journey filled with highs and lows, professional achievements, and personal challenges.

-

The Journey Begins

-

It all started on a Monday morning in Amman as I embarked on a journey to attend a Quality Control (QC) conference in Newcastle. The anticipation of presenting my work at an international forum filled me with excitement and nerves. The conference was scheduled for just one day, but the impact it had on me would last much longer.

-

A Successful Presentation

-

Tuesday arrived, and with it came the day of the conference. Armed with a PowerPoint presentation comprising over 130 slides, I delved into four hours of intense presenting. Despite the pressure, the conference was a resounding success. My project received positive feedback, and I felt a sense of accomplishment as I shared my work with colleagues from around the world.

-

The Toll of Travel

-

However, as I returned to Amman on Wednesday, I couldn't shake off a sense of exhaustion. Little did I know that the toll of travel would soon manifest itself in a most unexpected manner.

-

Thursday morning greeted me with heavy flu-like symptoms. It hit me like a ton of bricks. The combination of jet lag, long hours of presenting, and exposure to new environments had taken its toll on my immune system. I was bedridden, grappling with a chesty cough that seemed relentless.

-

The Show Must Go On

-

Despite my illness, there was no time for rest. The following week demanded my presence at a site meeting where I was tasked with condensing my extensive slide deck into a concise presentation of just 12 slides. The challenge was daunting, but I tackled it with determination.

-

Reflecting on the Journey

-

As I look back on the rollercoaster week that was, I'm struck by the juxtaposition of success and struggle. From the heights of presenting at an international conference to the lows of battling illness, it was a journey that tested my resilience and resolve.

-

But through it all, one thing remains clear: adversity only serves to make us stronger. Each obstacle we overcome, whether professional or personal, contributes to our growth and development.

-

So here's to the rollercoaster weeks, the ones filled with ups and downs, twists and turns. For it is in those moments of challenge that we discover the true extent of our capabilities.

-

As I upload this blog post using Hugo, I do so with a renewed sense of gratitude for the journey and all it has taught me. Here's to embracing the ride, wherever it may take us.

-]]>
- https://glenneth.org/content/posts/2024-05-01-amman-newcastle-journey.html - https://glenneth.org/content/posts/2024-05-01-amman-newcastle-journey.html - Wed, 01 May 2024 14:40:58 GMT - Glenn Thompson - work, travel -
-
+ + + + Glenn Thompson's Blog + Personal blog about programming, technology, and other interests + https://glenneth.org + + en-us + Sun, 28 Sep 2025 08:21:15 GMT + + + Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow + "Six months after my comprehensive development environment overview, I share the significant evolution to Guix Home and enhanced Emacs configurations that have transformed my daily workflow." + Introduction +

Six months ago, I shared a detailed look at my development environment in 2025, covering my hybrid approach with ArcoLinux, Guix package management, and Emacs-centered workflow. Since then, my setup has undergone a significant evolution driven by both choice and necessity.

+

The most significant change has been a transition to WSL2 on Windows 11 for my work environment, necessitated by corporate requirements. Rather than seeing this as a limitation, I've embraced it as an opportunity to refine my development approach, adopting Guix Home for complete environment management and building a custom Emacs installation from the master branch.

+

This evolution has taught me valuable lessons about adaptability and the power of declarative configuration in maintaining consistency across different underlying systems.

+

The Guix Home Revolution

+

From Hybrid to Unified

+

In March, I described my hybrid approach using both pacman/AUR and Guix for different aspects of my system. While this worked well, I found myself constantly managing the boundary between system and user packages, dealing with occasional conflicts, and maintaining separate configuration files.

+

Guix Home changed everything. Now I can declaratively manage:

+
    +
  • All my development tools and applications
  • +
  • Shell configuration and environment variables
  • +
  • Dotfiles and configuration files
  • +
  • Services and background processes
  • +
  • Desktop environment customizations
  • +
+

Current Guix Home Configuration

+

My home-configuration.scm has become the single source of truth for my development environment, particularly focused on Scheme/Guile development:

+
;; Guix Home configuration for Glenn's Scheme development environment
+
+(use-modules (gnu home)
+             (gnu packages)
+             (gnu services)
+             (gnu home services)
+             (gnu home services shells)
+             (gnu home services guix)
+             (gnu home services mcron)
+             (guix gexp))
+
+(home-environment
+  ;; Packages to install in the home environment
+  (packages (specifications->packages 
+             '(;; System essentials
+               "glibc-locales"
+               
+               ;; Scheme/Guile development environment
+               "guile-next"        ; Latest Guile development version
+               "guile-hoot"        ; Scheme to WebAssembly compiler
+               "guile-goblins"     ; Distributed programming environment
+               "guile-lib"         ; Useful Guile libraries
+               "guile-reader"      ; Reader extensions for Guile
+               "guile-json"        ; JSON support for Guile
+               
+               ;; Development tools  
+               ;; Note: Using custom-built Emacs 31.0.50 installation
+               "git"               ; Version control
+               "make"              ; Build system
+               "gcc-toolchain"     ; C compiler and tools
+               "pkg-config"        ; Package configuration
+               "texinfo"           ; Documentation system
+               "rlwrap")))         ; Readline wrapper for better REPL experience
+
+  ;; Services for the home environment
+  (services
+   (list
+    ;; Set up environment variables for Scheme development
+    (simple-service 'scheme-dev-env-vars
+                    home-environment-variables-service-type
+                    '(("EDITOR" . "emacs")
+                      ("GUILE_LOAD_PATH" . "$HOME/.guix-home/profile/share/guile/site/3.0:$GUILE_LOAD_PATH")
+                      ("GUILE_LOAD_COMPILED_PATH" . "$HOME/.guix-home/profile/lib/guile/3.0/site-ccache:$GUILE_LOAD_COMPILED_PATH")
+                      ("GUIX_LOCPATH" . "$HOME/.guix-home/profile/lib/locale")
+                      ("GUILE_AUTO_COMPILE" . "1")
+                      ("GUILE_WARN_DEPRECATED" . "detailed")))
+
+    ;; Add a simple mcron job for keeping system updated
+    (simple-service 'update-reminder
+                    home-mcron-service-type
+                    (list #~(job "0 12 * * 0"  ; Every Sunday at noon
+                                "echo 'Consider running: guix pull && guix home reconfigure ~/.config/guix/home-configuration.scm'"))))))
+
+

Benefits Realized

+

The transition to Guix Home has delivered on its promises:

+

Complete Reproducibility: I can now recreate my entire user environment on any machine with a single command: guix home reconfigure home-configuration.scm

+

Atomic Updates: Changes to my environment are atomic - either they work completely or roll back cleanly. No more broken states from partial updates.

+

Version Control Everything: My entire environment configuration lives in Git, with meaningful commit messages tracking every change to my setup.

+

Effortless Rollbacks: When an update breaks something, guix home roll-back instantly restores the previous working state.

+

Dependency Isolation: Each application gets exactly the dependencies it needs, eliminating conflicts between different tools requiring different library versions.

+

Enhanced Emacs Workflow

+

Custom Emacs Build from Master

+

One of the most significant changes in my setup has been building Emacs from the master branch rather than relying on distribution packages. This decision was driven by several factors:

+
    +
  • Latest Features: Access to cutting-edge features and improvements before they reach stable releases
  • +
  • WSL2 Optimization: Better integration with the WSL2 environment through custom compilation flags
  • +
  • Performance Tuning: Ability to optimize the build for my specific use case and hardware
  • +
+

Building Emacs 31.0.50 from source on WSL2 Ubuntu has given me a more responsive and feature-rich editing environment, particularly for Scheme development where the latest improvements in language support make a noticeable difference.

+

Configuration Management Evolution

+

While I was already using Emacs extensively in March, my configuration approach has matured significantly. I've moved from a monolithic configuration to a modular, feature-based system that's easier to maintain and debug.

+

New Emacs Enhancements

+

Improved LSP Integration: My language server setup now provides more consistent and reliable code intelligence across all my projects.

+

Enhanced Org Mode Workflow: I've integrated Org mode more deeply into my daily workflow for:

+
    +
  • Project planning and tracking
  • +
  • Meeting notes and documentation
  • +
  • Time tracking and productivity analysis
  • +
  • Knowledge management and linking
  • +
+

Better Terminal Integration: Using vterm and multi-vterm, I now have seamless terminal integration within Emacs, reducing context switching.

+

Refined Completion System: My completion setup with Vertico, Consult, and Marginalia has been fine-tuned for faster, more intuitive navigation.

+

Development Workflow Improvements

+

Project Management: Using projectile with enhanced project templates and automated setup scripts.

+

Code Quality: Integrated formatting, linting, and testing directly into my editing workflow with immediate feedback.

+

Documentation: Streamlined documentation generation and maintenance using Org mode's export capabilities.

+

Workflow Integration Benefits

+

Seamless Environment Switching

+

With Guix Home managing my entire environment, switching between different project contexts has become effortless. Each project can specify its exact dependencies, and Guix ensures they're available without affecting other projects.

+

Consistent Across Machines

+

Whether I'm working on my desktop, laptop, or a remote server, my environment is identical. This consistency has eliminated the "works on my machine" problem entirely.

+

Simplified Onboarding

+

Setting up a new development machine now takes minutes instead of hours. Clone my configuration repository, run guix home reconfigure, and everything is ready.

+

Challenges and Solutions

+

Learning Curve

+

Challenge: Guix Home's declarative approach required rethinking how I manage my environment.

+

Solution: Incremental migration, starting with simple configurations and gradually adding complexity as I became more comfortable with the system.

+

Documentation Gaps

+

Challenge: Guix Home is relatively new, with fewer examples and tutorials compared to traditional dotfile management.

+

Solution: Active participation in the Guix community, reading source code, and documenting my own discoveries.

+

Integration Complexity

+

Challenge: Some applications required custom integration work to play nicely with Guix Home.

+

Solution: Creating custom service definitions and contributing them back to the community when possible.

+

Performance and Productivity Impact

+

The move to Guix Home has had measurable impacts on my productivity:

+
    +
  • Reduced Setup Time: New project environments spin up in seconds
  • +
  • Fewer Context Switches: Everything I need is consistently available
  • +
  • Less Debugging: Reproducible environments mean fewer environment-related issues
  • +
  • Improved Focus: Less time managing tools means more time creating
  • +
+

Future Directions

+

Looking ahead, I'm exploring:

+

Custom Guix Channels: Creating personal channels for specialized tools and configurations not yet in the main Guix repository.

+

Advanced Service Integration: Developing more sophisticated service definitions for complex development workflows.

+

Cross-Machine Synchronization: Using Guix Home with remote development servers and cloud environments.

+

Community Contributions: Sharing useful service definitions and configurations with the broader Guix community.

+

Lessons Learned

+

Embrace Gradual Migration

+

Don't try to convert everything at once. Start with core tools and gradually expand your Guix Home configuration as you become more comfortable with the system.

+

Document Everything

+

Keep detailed notes about your configuration choices. The declarative nature of Guix Home makes it easy to forget why you made certain decisions.

+

Engage with the Community

+

The Guix community is incredibly helpful and knowledgeable. Don't hesitate to ask questions and share your experiences.

+

Version Control is Essential

+

Treat your Guix Home configuration like any other important code - use meaningful commit messages, create branches for experiments, and maintain good version control hygiene.

+

Conclusion

+

The evolution from my March setup to the current Guix Home-based environment represents more than just a tool change - it's a fundamental shift in how I think about development environment management. The move from imperative to declarative configuration has brought a level of reliability and reproducibility that has transformed my daily workflow.

+

For anyone considering similar changes, I'd recommend starting small and gradually expanding your declarative configuration. The initial learning curve is worth the long-term benefits of having a truly reproducible, version-controlled development environment.

+

The combination of Guix Home for environment management and a refined Emacs configuration has created a development setup that feels both powerful and effortless. It's a foundation I'm confident will serve me well as my projects and requirements continue to evolve.

+

What aspects of environment management do you find most challenging? Have you experimented with declarative configuration approaches? I'd love to hear about your experiences and any questions you might have about making similar transitions.

+]]>
+ https://glenneth.org/content/posts/2025-09-28-dev-environment-evolution-guix-home.html + https://glenneth.org/content/posts/2025-09-28-dev-environment-evolution-guix-home.html + Invalid Date + Glenn Thompson + ["development", "guix", "guix-home", "emacs", "workflow", "productivity", "evolution"] +
+
\ No newline at end of file diff --git a/deploy/index.html b/deploy/index.html index 4123a50..9d1fd43 100644 --- a/deploy/index.html +++ b/deploy/index.html @@ -58,178 +58,216 @@

Blog Posts

-
- -
-
- Tech - webdevelopmentjavascriptstatic-sitelessons - - -
-

- - Lessons Learned: One Year with a Custom Static Site Generator - -

-

It's been just over a year since I transitioned from Haunt to my own custom static site generator for this website. What started as an experiment to gain more control over my publishing workflow has e...

-
- webdevelopmentjavascriptstatic-sitelessons -
-
- - -
-
- Tech - developmentguixtoolsworkflowproductivityweb - - -
-

- - My Development Environment in 2025: From Editor to Deployment - -

-

The tools we use shape how we work. Over the years, my development environment has evolved alongside my technical journey through different programming languages, paradigms, and projects. This post of...

-
- developmentguixtoolsworkflowproductivityweb -
-
- - -
-
- Tech - webdevelopmentjavascriptstatic-sitehauntguilehugo - - -
-

- - From Hugo to Haunt to Custom: My Journey in Static Site Generation - -

-

My journey with static site generators has been one of continuous learning and evolution. It started with Hugo, transitioned through Haunt, and has now led me to build my own custom solution. Each ste...

-
- webdevelopmentjavascriptstatic-sitehauntguilehugo -
-
- - -
-
- Tech - techguileschemedevelopmentfunctional-programming - - -
-

- - Beyond Theory: Building Practical Tools with Guile Scheme - -

-

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world pro...

-
- techguileschemedevelopmentfunctional-programming -
-
- - -
-
- Tech - personaltechguileschemegnudevelopment - - -
-

- - A Journey into Scheme - -

-

I've spent my career as an electrical engineer, not a software developer. However, my recent journey in to GNU/Liniux required a tool for managing symlinks, and that's how I began learning Scheme—spec...

-
- personaltechguileschemegnudevelopment -
-
- - -
-
- Tech - personaltechgnuguixswaywmnvidia - - -
-

- - A Journey Through GNU Guix: From Installation to Returning to Arch Linux - -

-

As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey...

-
- personaltechgnuguixswaywmnvidia -
-
- - -
-
- Tech - personaltechkeyboardsglove80 - - -
-

- - Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix - -

-

Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation.

-
- personaltechkeyboardsglove80 -
-
- - -
-
- Tech - worktravel - - -
-

- - A Rollercoaster Week: From Amman to Newcastle, and back again - -

-

Two weeks ago was a whirlwind of events, taking me from the conforting embrace of Amman, Jordan to the vibrant streets of Newcastle, England. It was a journey filled with highs and lows, professional...

-
- worktravel -
-
- - -
-
- Tech - personaltechkeyboardsglove80 - - -
-

- - Aesthetic Meets Ergonomics: My Deep Dive into the Glove80 Keyboard - -

-

As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant...

-
- personaltechkeyboardsglove80 -
-
- +
+ +
+
+ Tech + developmentguixguix-homeemacsworkflowproductivityevolution + + +
+

+ + Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow + +

+

Six months ago, I shared a detailed look at my development environment in 2025, covering my hybrid approach with ArcoLinux, Guix package management, and Emacs-centered workflow. Since then, my setup h...

+
+ developmentguixguix-homeemacsworkflowproductivityevolution +
+
+ + +
+
+ Tech + communitywebringsystemcraftersreflection + + +
+

+ + One Year of Craftering: Building Connections in the System Crafters Community + +

+

Next Thursday, 03-APR-2025, marks the first anniversary of the Craftering webring, a vibrant community initiative started by shom that connects personal websites and blogs within the System Crafters c...

+
+ communitywebringsystemcraftersreflection +
+
+ + +
+
+ Tech + webdevelopmentjavascriptstatic-sitelessons + + +
+

+ + Lessons Learned: One Year with a Custom Static Site Generator + +

+

It's been just over a year since I transitioned from Haunt to my own custom static site generator for this website. What started as an experiment to gain more control over my publishing workflow has e...

+
+ webdevelopmentjavascriptstatic-sitelessons +
+
+ + +
+
+ Tech + developmentguixtoolsworkflowproductivityweb + + +
+

+ + My Development Environment in 2025: From Editor to Deployment + +

+

The tools we use shape how we work. Over the years, my development environment has evolved alongside my technical journey through different programming languages, paradigms, and projects. This post of...

+
+ developmentguixtoolsworkflowproductivityweb +
+
+ + +
+
+ Tech + webdevelopmentjavascriptstatic-sitehauntguilehugo + + +
+

+ + From Hugo to Haunt to Custom: My Journey in Static Site Generation + +

+

My journey with static site generators has been one of continuous learning and evolution. It started with Hugo, transitioned through Haunt, and has now led me to build my own custom solution. Each ste...

+
+ webdevelopmentjavascriptstatic-sitehauntguilehugo +
+
+ + +
+
+ Tech + techguileschemedevelopmentfunctional-programming + + +
+

+ + Beyond Theory: Building Practical Tools with Guile Scheme + +

+

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world pro...

+
+ techguileschemedevelopmentfunctional-programming +
+
+ + +
+
+ Tech + personaltechguileschemegnudevelopment + + +
+

+ + A Journey into Scheme + +

+

I've spent my career as an electrical engineer, not a software developer. However, my recent journey in to GNU/Liniux required a tool for managing symlinks, and that's how I began learning Scheme—spec...

+
+ personaltechguileschemegnudevelopment +
+
+ + +
+
+ Tech + personaltechgnuguixswaywmnvidia + + +
+

+ + A Journey Through GNU Guix: From Installation to Returning to Arch Linux + +

+

As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey...

+
+ personaltechgnuguixswaywmnvidia +
+
+ + +
+
+ Tech + personaltechkeyboardsglove80 + + +
+

+ + Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix + +

+

Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation.

+
+ personaltechkeyboardsglove80 +
+
+ + +
+
+ Tech + worktravel + + +
+

+ + A Rollercoaster Week: From Amman to Newcastle, and back again + +

+

Two weeks ago was a whirlwind of events, taking me from the conforting embrace of Amman, Jordan to the vibrant streets of Newcastle, England. It was a journey filled with highs and lows, professional...

+
+ worktravel +
+
+ + +
+
+ Tech + personaltechkeyboardsglove80 + + +
+

+ + Aesthetic Meets Ergonomics: My Deep Dive into the Glove80 Keyboard + +

+

As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant...

+
+ personaltechkeyboardsglove80 +
+
+
diff --git a/deploy/js/md-to-html.js b/deploy/js/md-to-html.js index 13326be..84b6f63 100644 --- a/deploy/js/md-to-html.js +++ b/deploy/js/md-to-html.js @@ -223,15 +223,28 @@ async function updateIndexWithSummaries() { // Extract metadata const metadata = {}; - content.replace(/^---\n([\s\S]*?)\n---\n/, (_, frontMatter) => { - frontMatter.split('\n').forEach(line => { - const [key, ...valueParts] = line.split(':'); - if (key && valueParts.length > 0) { - metadata[key.trim()] = valueParts.join(':').trim(); + // More flexible regex to handle different line endings + const frontMatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/); + if (frontMatterMatch) { + const frontMatter = frontMatterMatch[1]; + frontMatter.split(/\r?\n/).forEach(line => { + const colonIndex = line.indexOf(':'); + if (colonIndex > 0) { + const key = line.substring(0, colonIndex).trim(); + let value = line.substring(colonIndex + 1).trim(); + + // Remove quotes if present + if ((value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'"))) { + value = value.slice(1, -1); + } + + if (key && value) { + metadata[key] = value; + } } }); - return ''; - }); + } // Extract summary const summary = extractSummary(content); @@ -239,18 +252,45 @@ async function updateIndexWithSummaries() { // Parse and format the date let formattedDate = ''; let isoDate = ''; + + if (!metadata.date) { + console.warn(`No date found for ${file}`); + continue; + } + try { - // Handle date formats like "2024-04-08 16:50" or "2024-04-08" - const dateStr = metadata.date.split(' ')[0]; + let dateStr = ''; + + // Handle different date formats + if (typeof metadata.date === 'string') { + // String format: "2024-04-08 16:50" or "2024-04-08" + dateStr = metadata.date.split(' ')[0]; + } else if (typeof metadata.date === 'number') { + // Number format: 2025-04-02 (YAML parsed as number) + dateStr = metadata.date.toString(); + } else if (metadata.date instanceof Date) { + // Date object + dateStr = metadata.date.toISOString().split('T')[0]; + } else { + // Fallback: convert to string and extract date part + dateStr = String(metadata.date).split(' ')[0]; + } + const date = new Date(dateStr); - formattedDate = date.toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' - }); - isoDate = dateStr; + if (!isNaN(date.getTime())) { + formattedDate = date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + }); + isoDate = dateStr; + } else { + console.warn(`Invalid date format for ${file}: ${metadata.date} (type: ${typeof metadata.date})`); + continue; + } } catch (e) { console.error(`Error parsing date for ${file}:`, e); + continue; } // Parse tags diff --git a/dist/styles.css b/dist/styles.css index 039e244..cda0fb4 100644 --- a/dist/styles.css +++ b/dist/styles.css @@ -1,1597 +1 @@ -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -/* -! tailwindcss v3.4.15 | MIT License | https://tailwindcss.com -*/ - -/* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #e5e7eb; - /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -5. Use the user's configured `sans` font-feature-settings by default. -6. Use the user's configured `sans` font-variation-settings by default. -7. Disable tap highlights on iOS -*/ - -html, -:host { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: monospace, system-ui; - /* 4 */ - font-feature-settings: normal; - /* 5 */ - font-variation-settings: normal; - /* 6 */ - -webkit-tap-highlight-color: transparent; - /* 7 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font-family by default. -2. Use the user's configured `mono` font-feature-settings by default. -3. Use the user's configured `mono` font-variation-settings by default. -4. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: monospace; - /* 1 */ - font-feature-settings: normal; - /* 2 */ - font-variation-settings: normal; - /* 3 */ - font-size: 1em; - /* 4 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-feature-settings: inherit; - /* 1 */ - font-variation-settings: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - font-weight: inherit; - /* 1 */ - line-height: inherit; - /* 1 */ - letter-spacing: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -input:where([type='button']), -input:where([type='reset']), -input:where([type='submit']) { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Reset default styling for dialogs. -*/ - -dialog { - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ - -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* Make elements with the HTML hidden attribute stay hidden by default */ - -[hidden]:where(:not([hidden="until-found"])) { - display: none; -} - -html { - scroll-behavior: smooth; -} - -body { - --tw-text-opacity: 1; - color: rgb(166 172 205 / var(--tw-text-opacity, 1)); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -h1, h2, h3, h4, h5, h6 { - font-family: monospace, serif; -} - -.prose { - color: #A6ACCD; - max-width: none; -} - -.prose :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -.prose :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-lead); - font-size: 1.25em; - line-height: 1.6; - margin-top: 1.2em; - margin-bottom: 1.2em; -} - -.prose :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #82AAFF; - text-decoration: none; - font-weight: 500; -} - -.prose :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)):hover { - color: #C792EA; -} - -.prose :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #C792EA; - font-weight: 600; -} - -.prose :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -.prose :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -.prose :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -.prose :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-alpha; -} - -.prose :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-alpha; -} - -.prose :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -.prose :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -.prose :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; -} - -.prose :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: lower-roman; -} - -.prose :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: decimal; -} - -.prose :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - list-style-type: upper-roman; - margin-top: 1.25em; - margin-bottom: 1.25em; - padding-inline-start: 1.625em; -} - -.prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - font-weight: 400; - color: var(--tw-prose-counters); -} - -.prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { - color: var(--tw-prose-bullets); -} - -.prose :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - margin-top: 1.25em; -} - -.prose :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-color: var(--tw-prose-hr); - border-top-width: 1px; - margin-top: 3em; - margin-bottom: 3em; -} - -.prose :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-style: italic; - color: #A6ACCD; - border-inline-start-width: 0.25rem; - border-inline-start-color: var(--tw-prose-quote-borders); - quotes: "\201C""\201D""\2018""\2019"; - margin-top: 1.6em; - margin-bottom: 1.6em; - padding-inline-start: 1em; - border-left-color: #3D4857; - background-color: #2E3C4E; - border-radius: 5px; -} - -.prose :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: open-quote; -} - -.prose :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: close-quote; -} - -.prose :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #C792EA; - font-weight: 800; - font-size: 2.25em; - margin-top: 0; - margin-bottom: 0.8888889em; - line-height: 1.1111111; - font-family: monospace; -} - -.prose :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 900; - color: inherit; -} - -.prose :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #C792EA; - font-weight: 700; - font-size: 1.5em; - margin-top: 2em; - margin-bottom: 1em; - line-height: 1.3333333; - font-family: monospace; -} - -.prose :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 800; - color: inherit; -} - -.prose :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #C792EA; - font-weight: 600; - font-size: 1.25em; - margin-top: 1.6em; - margin-bottom: 0.6em; - line-height: 1.6; - font-family: monospace; -} - -.prose :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -.prose :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #C792EA; - font-weight: 600; - margin-top: 1.5em; - margin-bottom: 0.5em; - line-height: 1.5; - font-family: monospace; -} - -.prose :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 700; - color: inherit; -} - -.prose :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - display: block; - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - font-weight: 500; - font-family: inherit; - color: var(--tw-prose-kbd); - box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); - font-size: 0.875em; - border-radius: 0.3125rem; - padding-top: 0.1875em; - padding-inline-end: 0.375em; - padding-bottom: 0.1875em; - padding-inline-start: 0.375em; -} - -.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #C792EA; - font-weight: 600; - font-size: 0.875em; - background-color: #2A3446; - font-family: monospace; - border-radius: 5px; - padding: 0.2em; -} - -.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: ""; -} - -.prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: ""; -} - -.prose :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.875em; -} - -.prose :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; - font-size: 0.9em; -} - -.prose :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: inherit; -} - -.prose :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: #A6ACCD; - background-color: #2A3446; - overflow-x: auto; - font-weight: 400; - font-size: 0.875em; - line-height: 1.7142857; - margin-top: 1.7142857em; - margin-bottom: 1.7142857em; - border-radius: 5px; - padding-top: 0.8571429em; - padding-inline-end: 1.1428571em; - padding-bottom: 0.8571429em; - padding-inline-start: 1.1428571em; - font-family: monospace; -} - -.prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: transparent; - border-width: 0; - border-radius: 0; - padding: 0; - font-weight: inherit; - color: inherit; - font-size: inherit; - font-family: inherit; - line-height: inherit; -} - -.prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { - content: none; -} - -.prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: none; -} - -.prose :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - width: 100%; - table-layout: auto; - margin-top: 2em; - margin-bottom: 2em; - font-size: 0.875em; - line-height: 1.7142857; - background-color: #283544; - border-color: #4A596E; -} - -.prose :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-th-borders); -} - -.prose :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-headings); - font-weight: 600; - vertical-align: bottom; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -.prose :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 1px; - border-bottom-color: var(--tw-prose-td-borders); -} - -.prose :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-bottom-width: 0; -} - -.prose :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: baseline; -} - -.prose :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - border-top-width: 1px; - border-top-color: var(--tw-prose-th-borders); -} - -.prose :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - vertical-align: top; -} - -.prose :where(th, td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - text-align: start; -} - -.prose :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -.prose :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - color: var(--tw-prose-captions); - font-size: 0.875em; - line-height: 1.4285714; - margin-top: 0.8571429em; -} - -.prose { - --tw-prose-body: #374151; - --tw-prose-headings: #111827; - --tw-prose-lead: #4b5563; - --tw-prose-links: #111827; - --tw-prose-bold: #111827; - --tw-prose-counters: #6b7280; - --tw-prose-bullets: #d1d5db; - --tw-prose-hr: #e5e7eb; - --tw-prose-quotes: #111827; - --tw-prose-quote-borders: #e5e7eb; - --tw-prose-captions: #6b7280; - --tw-prose-kbd: #111827; - --tw-prose-kbd-shadows: 17 24 39; - --tw-prose-code: #111827; - --tw-prose-pre-code: #e5e7eb; - --tw-prose-pre-bg: #1f2937; - --tw-prose-th-borders: #d1d5db; - --tw-prose-td-borders: #e5e7eb; - --tw-prose-invert-body: #d1d5db; - --tw-prose-invert-headings: #fff; - --tw-prose-invert-lead: #9ca3af; - --tw-prose-invert-links: #fff; - --tw-prose-invert-bold: #fff; - --tw-prose-invert-counters: #9ca3af; - --tw-prose-invert-bullets: #4b5563; - --tw-prose-invert-hr: #374151; - --tw-prose-invert-quotes: #f3f4f6; - --tw-prose-invert-quote-borders: #374151; - --tw-prose-invert-captions: #9ca3af; - --tw-prose-invert-kbd: #fff; - --tw-prose-invert-kbd-shadows: 255 255 255; - --tw-prose-invert-code: #fff; - --tw-prose-invert-pre-code: #d1d5db; - --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); - --tw-prose-invert-th-borders: #4b5563; - --tw-prose-invert-td-borders: #374151; - font-size: 1.25rem; - line-height: 1.4; -} - -.prose :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; - margin-bottom: 0; -} - -.prose :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -.prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -.prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0.375em; -} - -.prose :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -.prose :where(.prose > ul > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -.prose :where(.prose > ul > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -.prose :where(.prose > ol > li > p:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; -} - -.prose :where(.prose > ol > li > p:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 1.25em; -} - -.prose :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.75em; - margin-bottom: 0.75em; -} - -.prose :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; -} - -.prose :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0.5em; - padding-inline-start: 1.625em; -} - -.prose :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -.prose :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -.prose :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-top: 0.5714286em; - padding-inline-end: 0.5714286em; - padding-bottom: 0.5714286em; - padding-inline-start: 0.5714286em; -} - -.prose :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-start: 0; -} - -.prose :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - padding-inline-end: 0; -} - -.prose :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 2em; - margin-bottom: 2em; -} - -.prose :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-top: 0; -} - -.prose :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - margin-bottom: 0; -} - -.prose :where(th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: #374A62; - color: #C792EA; -} - -.prose :where(tr:nth-child(even)):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: #2C3B4C; -} - -.prose :where(tr:hover):not(:where([class~="not-prose"],[class~="not-prose"] *)) { - background-color: #374A62; -} - -.nav-link { - display: inline-flex; - align-items: center; - padding-left: 0.25rem; - padding-right: 0.25rem; - padding-top: 0.25rem; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 500; - --tw-text-opacity: 1; - color: rgb(130 170 255 / var(--tw-text-opacity, 1)); - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.nav-link:hover { - --tw-text-opacity: 1; - color: rgb(199 146 234 / var(--tw-text-opacity, 1)); -} - -.static { - position: static; -} - -.fixed { - position: fixed; -} - -.z-50 { - z-index: 50; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; -} - -.mb-2 { - margin-bottom: 0.5rem; -} - -.mb-3 { - margin-bottom: 0.75rem; -} - -.mb-4 { - margin-bottom: 1rem; -} - -.mb-6 { - margin-bottom: 1.5rem; -} - -.mb-8 { - margin-bottom: 2rem; -} - -.mr-2 { - margin-right: 0.5rem; -} - -.mt-2 { - margin-top: 0.5rem; -} - -.mt-4 { - margin-top: 1rem; -} - -.mt-6 { - margin-top: 1.5rem; -} - -.flex { - display: flex; -} - -.inline-flex { - display: inline-flex; -} - -.grid { - display: grid; -} - -.hidden { - display: none; -} - -.h-16 { - height: 4rem; -} - -.h-5 { - height: 1.25rem; -} - -.w-5 { - width: 1.25rem; -} - -.w-full { - width: 100%; -} - -.max-w-2xl { - max-width: 42rem; -} - -.max-w-4xl { - max-width: 56rem; -} - -.max-w-7xl { - max-width: 80rem; -} - -.max-w-none { - max-width: none; -} - -.grid-cols-1 { - grid-template-columns: repeat(1, minmax(0, 1fr)); -} - -.flex-wrap { - flex-wrap: wrap; -} - -.items-center { - align-items: center; -} - -.justify-center { - justify-content: center; -} - -.justify-between { - justify-content: space-between; -} - -.gap-12 { - gap: 3rem; -} - -.gap-2 { - gap: 0.5rem; -} - -.gap-4 { - gap: 1rem; -} - -.gap-8 { - gap: 2rem; -} - -.space-y-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); -} - -.space-y-6 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); -} - -.rounded-full { - border-radius: 9999px; -} - -.rounded-lg { - border-radius: 0.5rem; -} - -.rounded-md { - border-radius: 0.375rem; -} - -.border { - border-width: 1px; -} - -.border-b { - border-bottom-width: 1px; -} - -.border-t { - border-top-width: 1px; -} - -.border-accent-blue { - --tw-border-opacity: 1; - border-color: rgb(130 170 255 / var(--tw-border-opacity, 1)); -} - -.border-palenight-400\/20 { - border-color: rgb(61 72 87 / 0.2); -} - -.bg-base-bg { - --tw-bg-opacity: 1; - background-color: rgb(41 45 62 / var(--tw-bg-opacity, 1)); -} - -.bg-base-darker { - --tw-bg-opacity: 1; - background-color: rgb(42 52 70 / var(--tw-bg-opacity, 1)); -} - -.bg-base-darker\/80 { - background-color: rgb(42 52 70 / 0.8); -} - -.p-6 { - padding: 1.5rem; -} - -.p-8 { - padding: 2rem; -} - -.px-2 { - padding-left: 0.5rem; - padding-right: 0.5rem; -} - -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} - -.px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; -} - -.py-1 { - padding-top: 0.25rem; - padding-bottom: 0.25rem; -} - -.py-12 { - padding-top: 3rem; - padding-bottom: 3rem; -} - -.py-16 { - padding-top: 4rem; - padding-bottom: 4rem; -} - -.py-3 { - padding-top: 0.75rem; - padding-bottom: 0.75rem; -} - -.pb-16 { - padding-bottom: 4rem; -} - -.pt-24 { - padding-top: 6rem; -} - -.text-center { - text-align: center; -} - -.font-serif { - font-family: monospace, serif; -} - -.text-3xl { - font-size: 1.875rem; - line-height: 2.25rem; -} - -.text-4xl { - font-size: 2.25rem; - line-height: 2.5rem; -} - -.text-base { - font-size: 1rem; - line-height: 1.5rem; -} - -.text-lg { - font-size: 1.125rem; - line-height: 1.75rem; -} - -.text-sm { - font-size: 0.875rem; - line-height: 1.25rem; -} - -.text-xl { - font-size: 1.25rem; - line-height: 1.75rem; -} - -.text-xs { - font-size: 0.75rem; - line-height: 1rem; -} - -.font-bold { - font-weight: 700; -} - -.font-medium { - font-weight: 500; -} - -.leading-8 { - line-height: 2rem; -} - -.tracking-tight { - letter-spacing: -0.025em; -} - -.text-accent-blue { - --tw-text-opacity: 1; - color: rgb(130 170 255 / var(--tw-text-opacity, 1)); -} - -.text-accent-cyan { - --tw-text-opacity: 1; - color: rgb(199 146 234 / var(--tw-text-opacity, 1)); -} - -.text-accent-purple { - --tw-text-opacity: 1; - color: rgb(199 146 234 / var(--tw-text-opacity, 1)); -} - -.text-accent-yellow { - --tw-text-opacity: 1; - color: rgb(255 203 107 / var(--tw-text-opacity, 1)); -} - -.text-palenight-100 { - --tw-text-opacity: 1; - color: rgb(166 172 205 / var(--tw-text-opacity, 1)); -} - -.text-palenight-200 { - --tw-text-opacity: 1; - color: rgb(130 170 255 / var(--tw-text-opacity, 1)); -} - -.text-palenight-300 { - --tw-text-opacity: 1; - color: rgb(74 89 110 / var(--tw-text-opacity, 1)); -} - -.text-palenight-50 { - --tw-text-opacity: 1; - color: rgb(166 172 205 / var(--tw-text-opacity, 1)); -} - -.shadow-lg { - --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.shadow-md { - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.shadow-sm { - --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.filter { - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} - -.backdrop-blur-sm { - --tw-backdrop-blur: blur(4px); - -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} - -.transition-colors { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.prose { - max-width: none; -} - -.prose img { - border-radius: 0.5rem; - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.hover\:border-accent-purple\/40:hover { - border-color: rgb(199 146 234 / 0.4); -} - -.hover\:bg-accent-blue:hover { - --tw-bg-opacity: 1; - background-color: rgb(130 170 255 / var(--tw-bg-opacity, 1)); -} - -.hover\:text-accent-cyan:hover { - --tw-text-opacity: 1; - color: rgb(199 146 234 / var(--tw-text-opacity, 1)); -} - -.hover\:text-accent-purple:hover { - --tw-text-opacity: 1; - color: rgb(199 146 234 / var(--tw-text-opacity, 1)); -} - -.hover\:text-base-bg:hover { - --tw-text-opacity: 1; - color: rgb(41 45 62 / var(--tw-text-opacity, 1)); -} - -@media (min-width: 640px) { - .sm\:ml-6 { - margin-left: 1.5rem; - } - - .sm\:flex { - display: flex; - } - - .sm\:space-x-8 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(2rem * var(--tw-space-x-reverse)); - margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse))); - } - - .sm\:px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; - } - - .sm\:pb-24 { - padding-bottom: 6rem; - } - - .sm\:pt-32 { - padding-top: 8rem; - } - - .sm\:text-6xl { - font-size: 3.75rem; - line-height: 1; - } -} - -@media (min-width: 768px) { - .md\:grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } -} - -@media (min-width: 1024px) { - .lg\:grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .lg\:grid-cols-3 { - grid-template-columns: repeat(3, minmax(0, 1fr)); - } - - .lg\:px-8 { - padding-left: 2rem; - padding-right: 2rem; - } -} +*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.15 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:monospace,system-ui;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{scroll-behavior:smooth}body{--tw-text-opacity:1;color:rgb(166 172 205/var(--tw-text-opacity,1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{font-family:monospace,serif}.prose{color:#a6accd;max-width:none}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#82aaff;text-decoration:none;font-weight:500}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#c792ea}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:#c792ea;font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:#a6accd;border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em;border-left-color:#3d4857;background-color:#2e3c4e;border-radius:5px}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:#c792ea;font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111;font-family:monospace}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:#c792ea;font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333;font-family:monospace}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:#c792ea;font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6;font-family:monospace}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:#c792ea;font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5;font-family:monospace}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:#c792ea;font-weight:600;font-size:.875em;background-color:#2a3446;font-family:monospace;border-radius:5px;padding:.2em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:""}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:""}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:#a6accd;background-color:#2a3446;overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:5px;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em;font-family:monospace}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857;background-color:#283544;border-color:#4a596e}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1.25rem;line-height:1.4}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose :where(th):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#374a62;color:#c792ea}.prose :where(tr:nth-child(2n)):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#2c3b4c}.prose :where(tr:hover):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#374a62}.nav-link{display:inline-flex;align-items:center;padding-left:.25rem;padding-right:.25rem;padding-top:.25rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.nav-link:hover{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.static{position:static}.fixed{position:fixed}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-16{height:4rem}.h-5{height:1.25rem}.w-5{width:1.25rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-7xl{max-width:80rem}.max-w-none{max-width:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-accent-blue{--tw-border-opacity:1;border-color:rgb(130 170 255/var(--tw-border-opacity,1))}.border-palenight-400\/20{border-color:rgba(61,72,87,.2)}.bg-base-bg{--tw-bg-opacity:1;background-color:rgb(41 45 62/var(--tw-bg-opacity,1))}.bg-base-darker{--tw-bg-opacity:1;background-color:rgb(42 52 70/var(--tw-bg-opacity,1))}.bg-base-darker\/80{background-color:rgba(42,52,70,.8)}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-16{padding-bottom:4rem}.pt-24{padding-top:6rem}.text-center{text-align:center}.font-serif{font-family:monospace,serif}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.leading-8{line-height:2rem}.tracking-tight{letter-spacing:-.025em}.text-accent-blue{--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1))}.text-accent-cyan,.text-accent-purple{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.text-accent-yellow{--tw-text-opacity:1;color:rgb(255 203 107/var(--tw-text-opacity,1))}.text-palenight-100{--tw-text-opacity:1;color:rgb(166 172 205/var(--tw-text-opacity,1))}.text-palenight-200{--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1))}.text-palenight-300{--tw-text-opacity:1;color:rgb(74 89 110/var(--tw-text-opacity,1))}.text-palenight-50{--tw-text-opacity:1;color:rgb(166 172 205/var(--tw-text-opacity,1))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.prose{max-width:none}.prose img{border-radius:.5rem;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:border-accent-purple\/40:hover{border-color:rgba(199,146,234,.4)}.hover\:bg-accent-blue:hover{--tw-bg-opacity:1;background-color:rgb(130 170 255/var(--tw-bg-opacity,1))}.hover\:text-accent-cyan:hover,.hover\:text-accent-purple:hover{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.hover\:text-base-bg:hover{--tw-text-opacity:1;color:rgb(41 45 62/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:ml-6{margin-left:1.5rem}.sm\:flex{display:flex}.sm\:space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem*var(--tw-space-x-reverse));margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)))}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-24{padding-bottom:6rem}.sm\:pt-32{padding-top:8rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}} \ No newline at end of file diff --git a/feed.xml b/feed.xml index 8407e33..dafaf85 100644 --- a/feed.xml +++ b/feed.xml @@ -1,1031 +1,170 @@ - - - - Glenn Thompson's Blog - Personal blog about programming, technology, and other interests - https://glenneth.org - - en-us - Wed, 02 Apr 2025 15:28:36 GMT - - - Aesthetic Meets Ergonomics: My Deep Dive into the Glove80 Keyboard - As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant transformation. The hands-on tasks of yesteryears were gradually replaced by a deluge of documentations—writing, reviewing, and endless typing. This shift brought with it an unwelcome companion: discomfort in my hands and wrists, a stark reminder of the ergonomic pitfalls of conventional keyboards. It was in this context that my quest for a more ergonomic typing solution began, leading me towards the world of ALICE layout keyboards, with the [Q10 Pro by Keychron](https://www.keychron.com/products/keychron-q10-pro-alice-layout-qmk-via-wireless-custom-mechanical-keyboard) being my initial foray into this new realm. - In the quest for the ultimate ergonomic keyboard, aesthetics often take a backseat to functionality. Yet, when I first laid eyes on the Glove80, I was struck by its elegant design—a refreshing departure from the utilitarian look typical of many ergonomic keyboards. Unlike the retro vibes of the Kinesis Advantage or the DIY aesthetics of most Dactyls, the Glove80 boasts a modern, sleek appearance that complements the contemporary design language of Apple, Google, and LG devices. With its clean lines and visually appealing legends, the Glove80 not only promises ergonomic comfort but does so with style, standing out amidst a sea of competitors. -

As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant transformation. The hands-on tasks of yesteryears were gradually replaced by a deluge of documentations—writing, reviewing, and endless typing. This shift brought with it an unwelcome companion: discomfort in my hands and wrists, a stark reminder of the ergonomic pitfalls of conventional keyboards. It was in this context that my quest for a more ergonomic typing solution began, leading me towards the world of ALICE layout keyboards, with the Q10 Pro by Keychron being my initial foray into this new realm.

-

However, the relief was partial, and the shadow of wrist strain persisted, urging me to delve deeper into the ergonomic keyboard universe. My search for a truly ergonomic solution brought me to the doorstep of the Glove80 by MoErgo. Boasting a unique split design, concave key wells, and a commitment to ergonomics that seemed almost tailor-made for my situation, the Glove80 held the promise of being the oasis I was desperately seeking in the desert of my wrist discomfort.

-

This journey from an ALICE layout keyboard user to a Glove80 enthusiast was not just about finding a better typing tool; it was about embracing a healthier typing posture and redefining my interaction with computers. After a month of integrating the Glove80 into my workflow, I'm ready to share my insights and experiences. This review will explore the initial adaptation period, the impact on my wrist health, and whether the Glove80 lives up to its promise as an ergonomic game-changer.

-

First Impressions: Feel and Experience

-

Upon beginning my typing journey with the Glove80, two aspects immediately stood out. The unique choc spacing, combined with finger-specific curves for each key column, facilitated effortless access to the bottom and number rows, as well as several function keys—without the need to move my hands. This ease of reach extended to the thumb keys, thoughtfully laid out in an arc to match the natural movement of my thumbs. Additionally, the keyboard's low profile on the desk encouraged a neutral wrist position, enhancing comfort during long typing sessions. These features converged to create a typing experience that was not just comfortable but intuitively aligned with natural hand movements.

-

The Details That Matter

-
Ergonomics at Its Core
-

The hallmark of the Glove80 is its ergonomics, designed to seamlessly integrate with the user's hand movements. After fine-tuning the tenting and tilting angles—made possible by the adjustable feet on each half of the keyboard—my hands naturally fell into the optimal typing position. The thoughtfully designed key layout meant that reaching for higher rows required merely straightening or curling my fingers, aided by the keyboard's choc spacing. Each column's unique height and curve catered to the different lengths of my fingers, further minimizing strain.

-
Key Innovations
-

The Glove80 introduces keycaps with a novel MCC profile, featuring raised sides and a central cylindrical channel, made from a slick POM material. This design supports the natural sliding of fingers across keys, reducing the need to lift hands while typing. The keyboard's thumb clusters are another highlight, offering six easily accessible keys per hand. This ergonomic layout ensures that most keys are within reach without stretching, a testament to the keyboard's user-centric design.

-
Beyond Typing: Features and Flexibility
-
    -
  • Tenting and Adjustability: The Glove80's customizable tenting angles, enhanced by sturdy locking nuts, ensure a tailored typing experience that can be finely adjusted to individual preferences.
  • -
  • Comfortable Palm Rest: The integrated, detachable palm rest offers additional comfort, catering to different typing styles with ease.
  • -
  • Switch Selection: While the standard Kailh choc switches are adequate, enthusiasts might prefer customizing their keyboard with preferred switches for an optimized typing feel. I opted for the lighter Kailh Choc V1, Red Pro Linear 35gf switches.
  • -
  • Keycaps: The high-quality POM keycaps, combined with attractive and durable legends, enhance the keyboard's tactile and visual appeal.
  • -
  • Tech-Savvy Features: From its easy-to-use firmware updates via a web interface to seamless Bluetooth connectivity and impressive battery life, the Glove80 is designed for a modern, wireless world.
  • -
  • RGB Lighting: While currently limited in customization, the RGB LEDs offer aesthetic versatility to match any setup.
  • -
-

Concluding Thoughts

-

The Glove80 keyboard represents a significant leap forward in ergonomic design, marrying aesthetics with unmatched comfort and functionality. Its thoughtful features—from the infinitely adjustable tenting to the innovative keycap design—set a new standard for what ergonomic keyboards can be. While there's room for improvement in switch selection and RGB customization, these are minor quibbles in an otherwise outstanding product. For those in search of ergonomic excellence without compromising on style or performance, the Glove80 is an investment worth making, promising a typing experience that's not just comfortable but truly enjoyable.

-]]>
- https://glenneth.org/content/posts/2024-04-08-glove80-review.html - https://glenneth.org/content/posts/2024-04-08-glove80-review.html - Invalid Date - "Glenn Thompson" - ["personal", "tech", "keyboards", "glove80"] -
- - - One Year of Craftering: Building Connections in the System Crafters Community - My First Pull Request - Next Thursday, 03-APR-2025, marks the first anniversary of the Craftering webring, a vibrant community initiative started by shom that connects personal websites and blogs within the System Crafters community. As one of the members of this webring, I've had the privilege of being part of this journey from its early days.

-

My First Pull Request

-

Joining Craftering was actually my first experience with the pull request workflow on Codeberg. As someone new to contributing to open source projects, I was initially intimidated by the process. However, shom took the time to walk me through each step, providing clear guidance and encouragement. This hands-on experience with git and PR workflows proved invaluable, making the technical aspects of contribution much less daunting.

-

As shom recently reflected, this kind of supportive onboarding was an intentional part of Craftering's design - creating opportunities for community members to learn and grow together through practical experience.

-

The Power of Connected Personal Spaces

-

The Craftering webring represents more than just a collection of links - it's a testament to the enduring value of personal websites and the importance of community-driven content. In an era dominated by social media platforms and algorithmic feeds, webrings offer a refreshing return to the web's roots: direct connections between individually crafted spaces.

-

Community Impact and Discoveries

-

Being part of the Craftering webring has enriched my own blogging experience in several ways:

-
    -
  1. Diverse Perspectives: Through the webring, I've discovered fellow creators sharing their experiences with everything from Emacs configurations to system design principles.

    -
  2. -
  3. Technical Cross-Pollination: Reading other members' blogs has introduced me to new tools and approaches. For instance, my recent transition to a custom static site generator was partly inspired by discussions and posts from the community.

    -
  4. -
  5. Consistent Motivation: Knowing that my blog is part of an interconnected community has encouraged more regular writing and sharing.

    -
  6. -
-

Technical Integration and RSS

-

One of the strengths of the Craftering webring is its embrace of RSS feeds, making it easy to follow updates from all community members. The webring's OPML file allows for quick subscription to all member feeds, creating a genuine sense of connection through content updates.

-

Looking Forward

-

As we celebrate this first year, it's exciting to see how the webring has grown and evolved. From the initial members to our current diverse group, each addition has brought new perspectives and valuable contributions to our community.

-

The success of Craftering demonstrates that the spirit of the early web - decentralized, personal, and community-driven - is very much alive. It shows that there's still tremendous value in maintaining personal spaces on the web, connected through shared interests and mutual respect for individual expression.

-

Join the Ring

-

If you maintain a personal website and are interested in connecting with like-minded individuals, consider joining the Craftering webring. The process is straightforward, and you'll be joining a supportive community of creators and thinkers who value personal expression and technical craftsmanship.

-

Here's to another year of crafting, sharing, and building connections in our corner of the web!

-]]>
- https://glenneth.org/content/posts/2025-04-04-one-year-of-craftering.html - https://glenneth.org/content/posts/2025-04-04-one-year-of-craftering.html - Wed, 02 Apr 2025 00:00:00 GMT - Glenn Thompson - [community, webring, systemcrafters, reflection] -
- - - Lessons Learned: One Year with a Custom Static Site Generator - In this post, I'll share the key lessons I've learned and insights I've gained from building and maintaining my own static site generator. While the technical details are interesting, the real value has been in the broader lessons about software development, user experience, and the balance between complexity and simplicity. - It's been just over a year since I transitioned from Haunt to my own custom static site generator for this website. What started as an experiment to gain more control over my publishing workflow has evolved into a valuable learning experience that has shaped how I approach web development projects.

-

In this post, I'll share the key lessons I've learned and insights I've gained from building and maintaining my own static site generator. While the technical details are interesting, the real value has been in the broader lessons about software development, user experience, and the balance between complexity and simplicity.

-

The Journey of Evolution

-

From Simple Beginnings

-

When I first built my static site generator, it was remarkably simple - just the essential features needed to convert my writing into a website. No extra features, no complex configurations, just the basics.

-

Today, the system has evolved considerably, but not through grand design or elaborate planning. Instead, it grew organically based on real needs and actual usage. This organic growth taught me valuable lessons about software development.

-

Lesson 1: Features Should Emerge from Usage

-

Many of the features in my static site generator emerged from actual writing and publishing needs:

-
    -
  1. The Draft System
    When I found myself working on multiple posts simultaneously, I needed a way to keep unfinished posts separate from published content. This led to the draft system, which now helps me manage my writing workflow effectively.

    -
  2. -
  3. Tag Organization
    As my collection of posts grew, I needed a way to organize related content. The tag system emerged naturally from this need, rather than being built upfront based on assumptions about how I might want to organize content.

    -
  4. -
  5. Content Validation
    After accidentally publishing a post with a malformed date and another with a duplicate title, I added validation checks. These weren't part of the initial design but came from real-world publishing mishaps.

    -
  6. -
-

Lesson 2: Simplicity Drives Performance

-

One of the most surprising lessons was how simplicity led to better performance:

-
    -
  1. Static HTML Generation
    By generating plain HTML files, the site loads quickly without any client-side processing. There's no JavaScript framework, no hydration, and no complex build process - just simple, fast HTML.

    -
  2. -
  3. Incremental Builds
    The build system only processes files that have changed. This means that even with hundreds of posts, updates are nearly instantaneous because only the necessary files are rebuilt.

    -
  4. -
  5. Minimal JavaScript
    By keeping JavaScript to a minimum and focusing on progressive enhancement, the site remains fast and accessible, even on slower connections.

    -
  6. -
-

Lesson 3: Developer Experience Matters

-

A good developer experience has proven crucial for maintaining motivation to write and publish:

-
    -
  1. Smart Port Management
    After encountering port conflicts with other services, I added automatic port detection and fallback. The system now checks if a port is in use and automatically finds the next available one, eliminating the frustration of manual port configuration.

    -
  2. -
  3. Clear Error Messages
    When something goes wrong (like a failed CSS build or HTML conversion), the system provides clear, actionable error messages. This immediate feedback helps quickly identify and fix issues during the development process.

    -
  4. -
  5. Automated Validation
    The build system validates the environment before starting, checking for required directories and dependencies. These checks catch common setup issues early, making the development process smoother.

    -
  6. -
-

Lesson 4: Content Drives Development

-

Perhaps the most important lesson has been letting content needs drive development:

-
    -
  1. Markdown Features
    I only added support for additional Markdown features (like tables and task lists) when I actually needed them in my writing. This prevented feature bloat and kept the system focused.

    -
  2. -
  3. RSS Feed
    The RSS feed wasn't part of the initial design but was added when the content volume grew enough to warrant it. This is a pattern I've seen repeatedly - features are most valuable when they solve real, existing needs.

    -
  4. -
  5. Summary Generation
    The way post summaries are generated has evolved based on the actual content I write. Initially, it was a simple character count, but it now intelligently extracts meaningful previews based on content structure.

    -
  6. -
-

Looking Forward

-

This project has taught me that the best software often evolves gradually in response to real needs rather than being built all at once from a grand design. It's a lesson that applies well beyond static site generators - it's about building software that serves actual needs rather than imagined ones.

-

Just today, while writing this post, I encountered and solved several development workflow issues. Instead of being frustrated by these challenges, I saw them as opportunities to improve the system. The resulting changes - like automatic port detection and better error handling - weren't part of any grand plan. They emerged naturally from real usage and made the system better in practical, meaningful ways.

-

The system isn't perfect, and it probably never will be. But it's continuously improving in ways that matter for my writing and publishing workflow. That, I've learned, is far more valuable than technical perfection.

-

If you're considering building your own tools, remember:

-
    -
  1. Start simple and let features emerge from actual usage
  2. -
  3. Focus on the experience - both for users and developers
  4. -
  5. Let real needs guide development
  6. -
  7. Embrace incremental improvements
  8. -
  9. Value simplicity - it often leads to better performance and maintainability
  10. -
  11. Use real-world problems as opportunities for improvement
  12. -
-

These lessons have influenced not just how I approach this project, but how I think about software development in general. Sometimes, the best insights come from the simplest projects - and often, they come right in the middle of writing about them.

-

Looking Back and Forward

-

Reflecting on this journey, the most valuable insight has been understanding that great software evolves naturally from real needs. Every feature in my static site generator—from the draft system to the validation checks—emerged from actual usage rather than upfront planning.

-

This experience has fundamentally changed how I approach software development. Instead of trying to build the perfect system from the start, I've learned to:

-
    -
  1. Start with the simplest solution that works
  2. -
  3. Let real usage guide feature development
  4. -
  5. Focus on maintainability over complexity
  6. -
  7. Prioritize the developer experience
  8. -
  9. Keep performance in mind at every step
  10. -
-

These principles have not only made my static site generator better but have also influenced how I approach every new project. Sometimes the best insights come from the simplest projects, and often they come right in the middle of writing about them.

-]]>
- https://glenneth.org/content/posts/2025-03-12-lessons-learned-custom-ssg.html - https://glenneth.org/content/posts/2025-03-12-lessons-learned-custom-ssg.html - Thu, 13 Mar 2025 00:00:00 GMT - Glenn Thompson - [web, development, javascript, static-site, lessons] -
- - - My Development Environment in 2025: From Editor to Deployment - A comprehensive look at my current development setup in 2025, covering everything from my GNU Guix system foundation to editor configurations, terminal tools, and deployment processes. - Introduction -

The tools we use shape how we work. Over the years, my development environment has evolved alongside my technical journey through different programming languages, paradigms, and projects. This post offers a snapshot of my current setup in early 2025, detailing the choices I've made and why they work for me.

-

System Foundation: ArcoLinux with GNU Guix

-

My journey to GNU Guix began through my exploration of Scheme programming, as I detailed in my GNU Guix Journey post. While I initially experimented with Guix System, I've settled on a hybrid approach: running Guix as a package manager on top of ArcoLinux (an Arch-based distribution).

-

Current Configuration Approach

-

I manage my development environment using a combination of Arch's pacman, AUR, and Guix's declarative package management. My Guix configuration lives in a Git repository, allowing me to:

-
    -
  • Track changes to my development environment over time
  • -
  • Reproduce my development setup on new hardware
  • -
  • Roll back to previous package states when needed
  • -
  • Share configuration snippets with the community
  • -
-

Key Packages and Tools

-

I maintain a hybrid package approach:

-

System packages (via pacman/AUR):

-
    -
  • Base system utilities and desktop environment
  • -
  • Graphics drivers and hardware support
  • -
  • Some GUI applications
  • -
-

Development tools (via Guix):

-
;; My primary development tools managed by Guix
-(specifications->manifest
- '("emacs" "git" "openssh" "ripgrep" "fd" "exa" "bat"
-   "guile" "node" "python" "gcc-toolchain" "make"
-   "nss-certs" "glibc-locales"))
-
-

This hybrid approach gives me the best of both worlds: Arch's extensive package repository and up-to-date system packages, combined with Guix's reproducible development environments.

-

Reproducibility Benefits

-

The reproducibility of Guix for development environments has been invaluable. I can:

-
    -
  • Spin up development environments with precise dependencies
  • -
  • Ensure consistent behavior across machines
  • -
  • Isolate project-specific dependencies using Guix environments
  • -
  • Share exact environment specifications with collaborators
  • -
-

Challenges and Solutions

-

Working with this hybrid approach isn't without challenges:

-
    -
  • Challenge: Keeping Guix packages in sync with system libraries
    Solution: Careful management of library paths and containerization when needed

    -
  • -
  • Challenge: Learning curve for Guix's declarative configuration
    Solution: Incremental adoption and community resources

    -
  • -
  • Challenge: Occasional conflicts between package managers
    Solution: Clear separation of responsibilities (system vs. development tools)

    -
  • -
-

Editor Environment: Emacs

-

After experimenting with various editors, I've settled on Emacs as my primary development environment. Its extensibility and Scheme-based configuration language (Emacs Lisp) align well with my interests.

-

Configuration Approach

-

I use a literate configuration with Org mode, which allows me to:

-
    -
  • Document my configuration choices
  • -
  • Organize settings by purpose rather than file
  • -
  • Selectively load components based on context
  • -
  • Share readable documentation with others
  • -
-

Key Extensions

-

My most valuable Emacs extensions include:

-
    -
  • Magit: Git interface that has transformed my version control workflow
  • -
  • LSP Mode: Language server integration for intelligent code assistance
  • -
  • Org Mode: For notes, task management, and literate programming
  • -
  • Projectile: Project navigation and management
  • -
  • Company: Completion framework
  • -
  • Consult/Vertico/Marginalia: Modern completion UI
  • -
  • Tree-sitter: Improved syntax highlighting and structural editing
  • -
-

Language-Specific Setups

-

For my primary languages:

-
    -
  • Scheme/Guile: Geiser for REPL integration
  • -
  • JavaScript/TypeScript: TypeScript LSP, prettier, eslint integration
  • -
  • Python: Pyright LSP, black formatting
  • -
  • Web Development: Web mode, emmet, css-mode
  • -
-

Productivity Enhancements

-

Some productivity boosters in my setup:

-
    -
  • Custom keybindings for frequent operations
  • -
  • Snippets for common code patterns
  • -
  • Template generation for new projects
  • -
  • Integration with system notifications
  • -
-

Terminal and CLI Tools

-

While Emacs handles many tasks, I still rely heavily on terminal tools for specific workflows.

-

Shell Configuration

-

I use Zsh with a custom configuration that provides:

-
    -
  • Intuitive aliases
  • -
  • Helpful prompts with Git integration
  • -
  • Command history management
  • -
  • Directory navigation shortcuts
  • -
-

Custom Scripts and Utilities

-

I've developed several custom scripts to streamline repetitive tasks:

-
    -
  • Project initialization templates
  • -
  • Deployment automation
  • -
  • System maintenance routines
  • -
  • Content management for this blog
  • -
-

Task Automation

-

For task automation, I use a combination of:

-
    -
  • Shell scripts for simple operations
  • -
  • Guile scripts for more complex logic
  • -
  • Make for build processes
  • -
  • Cron for scheduled tasks
  • -
-

Version Control Workflow

-

My Git workflow relies on:

-
    -
  • Branch-per-feature approach
  • -
  • Interactive rebasing for clean history
  • -
  • Commit message templates
  • -
  • Hooks for quality checks
  • -
-

Web Development Stack

-

As the creator of this website, my web development setup has been refined through experience.

-

Local Development Server

-

For local development, I use:

-
    -
  • Live-server for static sites
  • -
  • Custom Node.js servers for API development
  • -
  • Docker containers for complex dependencies
  • -
-

Build Tools and Processes

-

My build process typically involves:

-
    -
  • Tailwind CSS for styling
  • -
  • Minimal JavaScript bundling
  • -
  • Custom static site generation (as detailed in my previous post)
  • -
  • Automated optimization steps
  • -
-

Testing Approach

-

For testing, I employ:

-
    -
  • Jest for JavaScript unit tests
  • -
  • Cypress for end-to-end testing
  • -
  • Manual testing across devices and browsers
  • -
  • Accessibility validation tools
  • -
-

Browser Tools and Extensions

-

Essential browser tools include:

-
    -
  • Firefox Developer Edition as my primary browser
  • -
  • Chrome for cross-browser testing
  • -
  • DevTools for performance analysis
  • -
  • React and Redux DevTools
  • -
  • Accessibility checkers
  • -
-

Deployment Pipeline

-

My approach to deployment emphasizes security and reliability.

-

Secure Deployment Process

-

As you might have noticed from my .env.gpg file, I take security seriously:

-
    -
  • Credentials stored in GPG-encrypted files
  • -
  • Separate development and production configurations
  • -
  • Principle of least privilege for service accounts
  • -
  • Regular security audits
  • -
-

Automation Scripts

-

My deployment is automated through:

-
    -
  • Custom shell scripts for build and deploy
  • -
  • Validation steps before deployment
  • -
  • Rollback capabilities
  • -
  • Notification systems for success/failure
  • -
-

CI/CD Considerations

-

While not using a formal CI/CD pipeline for this personal site, I follow similar principles:

-
    -
  • Pre-commit checks for code quality
  • -
  • Automated testing before deployment
  • -
  • Consistent build environments
  • -
  • Deployment approval steps
  • -
-

Monitoring and Analytics

-

For site monitoring, I use:

-
    -
  • Simple analytics for privacy-respecting visitor tracking
  • -
  • Uptime monitoring
  • -
  • Performance metrics collection
  • -
  • Error logging and alerting
  • -
-

Future Improvements

-

My environment continues to evolve. Areas I'm exploring include:

-
    -
  • Further integration between Emacs and system tools
  • -
  • More comprehensive test automation
  • -
  • Expanded use of Guix channels for package management
  • -
  • Improved mobile development workflow
  • -
-

Conclusion

-

A development environment is deeply personal, reflecting both technical needs and individual preferences. Mine has evolved through years of experimentation, learning, and refinement.

-

The most important lesson I've learned is that tools should serve your workflow, not dictate it. Be willing to experiment, but also recognize when a tool is working well enough that further optimization yields diminishing returns.

-

I hope sharing my setup provides some inspiration for your own environment. I'd love to hear about your setup and what tools have made the biggest difference in your workflow.

-

What aspects of your development environment have you found most valuable? Are there tools or approaches you think I should consider? Let me know!

-]]>
- https://glenneth.org/content/posts/2025-03-08-my-dev-environment-2025.html - https://glenneth.org/content/posts/2025-03-08-my-dev-environment-2025.html - Sat, 08 Mar 2025 00:00:00 GMT - Glenn Thompson - development, guix, tools, workflow, productivity, web -
- - - From Hugo to Haunt to Custom: My Journey in Static Site Generation - A reflection on my evolving journey through static site generators - from Hugo to Haunt, and finally to building my own custom solution, highlighting the valuable lessons learned along the way. - My journey with static site generators has been one of continuous learning and evolution. It started with Hugo, transitioned through Haunt, and has now led me to build my own custom solution. Each step of this journey has taught me valuable lessons about web development, programming languages, and the importance of understanding the tools we use.

-

The Hugo Beginning

-

Like many "bloggers", I started with Hugo, a popular static site generator known for its speed and extensive theme ecosystem. Hugo served its purpose well, providing a robust platform for my blog with ready-made themes and a strong community.

-

The Transition to Haunt

-

My journey took an interesting turn when I joined the System Crafters Community. Through David Wilson's excellent course, Hands-On Guile Scheme for Beginners, I was introduced to the world of Scheme programming. This led me to adopt GNU Guix as my operating system, which naturally led me to Haunt, a static site generator written in Guile Scheme.

-

The transition to Haunt was motivated by several factors:

-
    -
  • Alignment with my growing interest in Scheme and functional programming
  • -
  • Integration with the GNU Guix ecosystem
  • -
  • The opportunity to write site configuration in Scheme
  • -
  • A desire for a simpler, more controllable setup
  • -
-

The Haunt Experience

-

Haunt offered a different perspective on site generation. Some highlights of my Haunt experience included:

-
    -
  • Writing site configuration in Scheme, which felt natural after learning Guile
  • -
  • Creating custom templates that matched my site's aesthetic needs
  • -
  • Learning to leverage Scheme's flexibility for site customization
  • -
  • Being part of a community that values simplicity and transparency
  • -
-

However, working with Haunt also presented challenges:

-
    -
  • Limited availability of ready-made templates
  • -
  • Need to create custom solutions for common features
  • -
  • Learning curve of Scheme for web development
  • -
-

The Move to Custom Development

-

As I became more comfortable with web development and gained a deeper understanding of static site generation, I felt ready for the next step: building my own static site generator. This decision wasn't about Haunt's limitations - it was about the desire to understand every aspect of my site's generation process and have complete control over its architecture.

-

The New Architecture

-

My custom solution combines the lessons learned from both Hugo and Haunt with modern web development practices:

-
    -
  • Modern JavaScript: Using Node.js and contemporary JavaScript tools
  • -
  • Markdown Processing: Leveraging the marked library for flexible content processing
  • -
  • Tailwind CSS: Adopting a utility-first approach to styling
  • -
  • Simple Build Process: A straightforward build script that handles all aspects of site generation
  • -
  • Development Server: Live reload functionality for immediate feedback
  • -
-

Benefits of the Custom Solution

-

Building my own solution has brought several advantages:

-
    -
  1. Complete Understanding: I now understand every aspect of my site's generation
  2. -
  3. Faster Iterations: Quick implementation of new features
  4. -
  5. Modern Development: Integration with current web development tools
  6. -
  7. Simplified Deployment: Streamlined process for updates
  8. -
  9. Better Performance: Only including features I actually need
  10. -
-

Learning Experience

-

This journey from Hugo through Haunt to a custom solution has taught me:

-
    -
  • The value of understanding different approaches to static site generation
  • -
  • The importance of choosing tools that align with your learning goals
  • -
  • How different programming paradigms (Go, Scheme, JavaScript) approach similar problems
  • -
  • The benefits of building your own tools when the learning opportunity outweighs convenience
  • -
-

Future Improvements

-

While my custom solution meets my current needs, I'm excited about potential improvements:

-
    -
  • Adding support for draft posts
  • -
  • Implementing a tag-based navigation system
  • -
  • Adding search functionality
  • -
  • Improving the build process
  • -
  • Adding image optimization
  • -
-

Conclusion

-

My journey from Hugo through Haunt to a custom solution reflects a common pattern in software development - starting with established tools, learning their principles, and eventually building your own solutions. Each step has been valuable:

-
    -
  • Hugo taught me about static site generators and their capabilities
  • -
  • Haunt introduced me to functional programming and the beauty of Scheme
  • -
  • Building my own solution has given me deep insights into web development
  • -
-

The source code for my site generator is available on GitHub. While it may not be the most feature-rich static site generator, it's perfectly tailored to my needs and represents a significant learning journey.

-

Remember, the goal of building your own tools isn't always to create something better than existing solutions - sometimes it's about the learning experience and creating something that perfectly fits your specific needs. Whether you're using Hugo, Haunt, or considering building your own solution, the most important thing is that it serves your purposes and helps you grow.

-]]>
- https://glenneth.org/content/posts/2025-01-02-from-haunt-to-custom.html - https://glenneth.org/content/posts/2025-01-02-from-haunt-to-custom.html - Thu, 02 Jan 2025 00:00:00 GMT - Glenn Thompson - web, development, javascript, static-site, haunt, guile, hugo -
- - - Beyond Theory: Building Practical Tools with Guile Scheme - Introduction - Beyond Theory: Building Practical Tools with Guile Scheme -

Introduction

-

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world problems is where the most valuable lessons emerge. This post explores what I've learned about building practical tools with Guile Scheme, sharing both successes and challenges along the way.

-

The Power of Modular Design

-

One of the most important lessons I learned was the value of modular design. Breaking down a program into focused, single-responsibility modules not only makes the code more maintainable but also helps in reasoning about the program's behavior. Here's how I structured stash:

-
(use-modules (ice-9 getopt-long)
-             (stash help)         ;; Help module
-             (stash colors)       ;; ANSI colors
-             (stash log)          ;; Logging module
-             (stash paths)        ;; Path handling module
-             (stash conflict)     ;; Conflict resolution module
-             (stash file-ops))    ;; File and symlink operations module
-
-

Each module has a specific responsibility:

-
    -
  • colors.scm: Handles ANSI color formatting for terminal output
  • -
  • conflict.scm: Manages conflict resolution when files already exist
  • -
  • file-ops.scm: Handles file system operations
  • -
  • help.scm: Provides usage information
  • -
  • log.scm: Manages logging operations
  • -
  • paths.scm: Handles path manipulation and normalization
  • -
-

Robust Path Handling

-

One of the first challenges in building a file management tool is handling paths correctly. Here's how I approached it:

-
(define (expand-home path)
-  "Expand ~ to the user's home directory."
-  (if (string-prefix? "~" path)
-      (string-append (getenv "HOME") (substring path 1))
-      path))
-
-(define (concat-path base path)
-  "Concatenate two paths, ensuring there are no double slashes."
-  (if (string-suffix? "/" base)
-      (string-append (string-drop-right base 1) "/" path)
-      (string-append base "/" path)))
-
-(define (ensure-config-path target-dir)
-  "Ensure that the target directory has .config appended, avoiding double slashes."
-  (let ((target-dir (expand-home target-dir)))
-    (if (string-suffix? "/" target-dir)
-        (set! target-dir (string-drop-right target-dir 1)))
-    (if (not (string-suffix? "/.config" target-dir))
-        (string-append target-dir "/.config")
-        target-dir)))
-
-

This approach ensures that:

-
    -
  • Home directory references (~) are properly expanded
  • -
  • Path concatenation doesn't create double slashes
  • -
  • Configuration paths are consistently structured
  • -
-

Interactive Conflict Resolution

-

Real-world tools often need to handle conflicts. I implemented an interactive conflict resolution system:

-
(define (prompt-user-for-action)
-  "Prompt the user to decide how to handle a conflict: overwrite (o), skip (s), or cancel (c)."
-  (display (color-message 
-    "A conflict was detected. Choose action - Overwrite (o), Skip (s), or Cancel (c): " 
-    yellow-text))
-  (let ((response (read-line)))
-    (cond
-      ((string-ci=? response "o") 'overwrite)
-      ((string-ci=? response "s") 'skip)
-      ((string-ci=? response "c") 'cancel)
-      (else
-       (display "Invalid input. Please try again.\n")
-       (prompt-user-for-action)))))
-
-

This provides a user-friendly interface for resolving conflicts while maintaining data safety.

-

Logging for Debugging and Auditing

-

Proper logging is crucial for debugging and auditing. I implemented a simple but effective logging system:

-
(define (current-timestamp)
-  "Return the current date and time as a formatted string."
-  (let* ((time (current-time))
-         (seconds (time-second time)))
-    (strftime "%Y-%m-%d-%H-%M-%S" (localtime seconds))))
-
-(define (log-action message)
-  "Log an action with a timestamp to the stash.log file."
-  (let ((log-port (open-file "stash.log" "a")))
-    (display (color-message 
-      (string-append "[" (current-timestamp) "] " message) 
-      green-text) log-port)
-    (newline log-port)
-    (close-port log-port)))
-
-

This logging system:

-
    -
  • Timestamps each action
  • -
  • Uses color coding for better readability
  • -
  • Maintains a persistent log file
  • -
  • Properly handles file operations
  • -
-

File Operations with Safety

-

When dealing with file system operations, safety is paramount. Here's how I handle moving directories:

-
(define (move-source-to-target source-dir target-dir)
-  "Move the entire source directory to the target directory, ensuring .config in the target path."
-  (let* ((target-dir (ensure-config-path target-dir))
-         (source-dir (expand-home source-dir))
-         (source-name (basename source-dir))
-         (target-source-dir (concat-path target-dir source-name)))
-    (if (not (file-exists? target-dir))
-        (mkdir target-dir #o755))
-    (if (file-exists? target-source-dir)
-        (handle-conflict target-source-dir source-dir delete-directory log-action)
-        (begin
-          (rename-file source-dir target-source-dir)
-          (display (format #f "Moved ~a to ~a\n" source-dir target-source-dir))
-          (log-action (format #f "Moved ~a to ~a" source-dir target-source-dir))))
-    target-source-dir))
-
-

This implementation:

-
    -
  • Ensures paths are properly formatted
  • -
  • Creates necessary directories
  • -
  • Handles conflicts gracefully
  • -
  • Logs all operations
  • -
  • Returns the new path for further operations
  • -
-

Lessons Learned

-

What Worked Well

-
    -
  1. Modular Design: Breaking the code into focused modules made it easier to maintain and test
  2. -
  3. Functional Approach: Using pure functions where possible made the code more predictable
  4. -
  5. Interactive Interface: Providing clear user prompts and colored output improved usability
  6. -
  7. Robust Logging: Detailed logging helped with debugging and understanding program flow
  8. -
-

Challenges Faced

-
    -
  1. Path Handling: Dealing with different path formats and edge cases required careful attention
  2. -
  3. Error States: Managing various error conditions while keeping the code clean
  4. -
  5. User Interface: Balancing between automation and user control
  6. -
  7. Documentation: Writing clear documentation that helps users understand the tool
  8. -
-

Moving Forward

-

Building stash has taught me that while functional programming principles are valuable, pragmatism is equally important. The key is finding the right balance between elegant functional code and practical solutions.

-

Resources

-
    -
  1. Guile Manual
  2. -
  3. My Previous Scheme Journey Post
  4. -
  5. System Crafters Community
  6. -
  7. Stash on Codeberg
  8. -
-

The code examples in this post are from my actual implementation of stash. Feel free to explore, use, and improve upon them!

-]]>
- https://glenneth.org/content/posts/2024-12-03-practical-scheme.html - https://glenneth.org/content/posts/2024-12-03-practical-scheme.html - Tue, 03 Dec 2024 07:00:00 GMT - Glenn Thompson - tech, guile, scheme, development, functional-programming -
- - - A Journey into Scheme - The course took me through the basics of Scheme, from simple expressions to more complex concepts like functions, recursion, and working with files. This structured learning environment gave me the confidence to start building stash. - My Journey into Scheme: Building a Simple Symlink Manager with Guile Scheme -

Introduction

-

I've spent my career as an electrical engineer, not a software developer. However, my recent journey in to GNU/Liniux required a tool for managing symlinks, and that's how I began learning Scheme—specifically Guile Scheme. I'm writing this post to share how I built stash, a utility that mimics GNU Stow's functionality, and how my learning journey was shaped by David Wilson's "Hands-On Guile Scheme for Beginners" course from System Crafters, more about this below.

-

How I Started with Scheme

-

My programming background was VERY limited, I produce documents in (La)Tex but I decided to take the plunge into learning Scheme, thanks to a course led by David Wilson from System Crafters. The course, "Hands-On Guile Scheme for Beginners", was incredibly helpful in making Scheme accessible even for someone like me, without a traditional programming background. I know (La)Tex isn't a programming language, it's typesetting. But how hard can it be? Right?

-

The course took me through the basics of Scheme, from simple expressions to more complex concepts like functions, recursion, and working with files. This structured learning environment gave me the confidence to start building stash.

-

The course was "instructor-led" with live meet-up sessions weekly. David has since made this course on-demand, and will be, if not already, available at the above link. Highly recommended if you are interested in taking your first steps with scheme.

-

Why Build Stash?

-

After completing David Wilson's course, I wanted to put my newly found Guile Scheme skills into practice with a real project. It wasn't enough just to understand the language conceptually—I needed to build something tangible that solved a problem I encountered regularly in my workflow. Writing stash gave me that opportunity. It allowed me to apply what I'd learned while also deepening my understanding of file manipulation, command-line tools, and conflict resolution—all within the Guile Scheme environment.

-

After migrating to GNU/Linux and speaking with other System Crafters Community members, I found I needed a way to manage symbolic links and organize directories. Existing tools like GNU Stow helped, but I wanted to learn how such tools are built. I decided to write my own version using Guile Scheme to enhance my understanding of the language and to have more control over the functionality.

-

The goal of stash is simple: allow users to move directories and create symlinks with conflict resolution, offering options to overwrite, back up, skip, or cancel the operation.

-

Breaking Down Stash

-

The core of stash revolves around:

-
    -
  1. Moving Directories: Using Scheme's file manipulation functions, I learned how to move directories and files around.
  2. -
  3. Creating Symlinks: I implemented functions to create symlinks to the moved directories, ensuring that the original structure remains accessible.
  4. -
  5. Conflict Resolution: One of the key features I wanted was handling conflicts when a file or symlink already exists at the target location. This required prompting the user for input and responding accordingly (backup, overwrite, skip, or cancel).
  6. -
-

Here's an excerpt of the core functionality that handles moving a source directory and creating a symlink:

-
;;; Helper function to move source to target
-(define (move-source-to-target source-dir target-dir)
-  "Move the entire source directory to the target directory."
-  (let* ((source-dir (expand-home source-dir))
-         (target-dir (expand-home target-dir))
-         (source-name (basename source-dir))
-         (target-source-dir (string-append target-dir "/" source-name)))
-    (if (file-exists? target-source-dir)
-        ;; Conflict handling here...
-        ...)
-    (rename-file source-dir target-source-dir)
-    (display (format #f "Moved ~a to ~a\n" source-dir target-source-dir))))
-
-

What I Learned

-

This project taught me a lot about not just Scheme, but programming in general:

-
    -
  • File and Directory Manipulation: Scheme's file handling functions were different from what I had experienced before, but they allowed for powerful manipulation of file systems.
  • -
  • Command-Line Utilities: Scheme isn't just a language for academic exercises; you can write real, useful command-line tools with it.
  • -
  • Problem Solving: From parsing command-line arguments to resolving conflicts with existing files, every part of the program required careful thought and consideration of edge cases.
  • -
-

Guile Scheme Support Resources

-
    -
  1. Guile Scheme Documentation
    The official documentation for Guile Scheme, which includes tutorials, references, and the Guile Manual.

    -
  2. -
  3. Guile Reference Manual
    A comprehensive manual covering core language concepts, libraries, and functions available in Guile Scheme.

    -
  4. -
  5. Scheme Wiki
    A community-maintained wiki that covers various Scheme dialects, including Guile Scheme, with tutorials, guides, and general information on Scheme programming.

    -
  6. -
  7. Guile at Schemers.org
    A site dedicated to Scheme with resources, libraries, tools, and documentation for Scheme and its implementations, including Guile.

    -
  8. -
  9. System Crafters
    Led by David Wilson, System Crafters provides tutorials and blog posts on Guile Scheme and other GNU tools.

    -
  10. -
  11. Guile Users Mailing List
    Join the Guile mailing list to ask questions and engage with the Guile Scheme community.

    -
  12. -
  13. Guile Cookbook
    An unofficial GitHub repository with practical code snippets and tips for Guile Scheme, covering various common use cases and tasks.

    -
  14. -
  15. #guile and #scheme on Libera Chat IRC
    A helpful IRC channel where you can connect with other Guile users for real-time support and advice.

    -
  16. -
  17. #systemcrafters on Libera Chat IRC
    A SUPER helpful IRC channel not only for guile and scheme, there are a huge variety of different people here. Tell them glenneth sent you.

    -
  18. -
-

Next Steps

-

I am still refining stash, especially around its conflict resolution system and the way it handles symbolic links. But it's in a usable state, and I'm excited to continue iterating on it. You can check out the code on Codeberg.

-

If you're curious about Scheme and how it can be used practically, I highly recommend checking out David Wilson's course. It's been instrumental in helping me grasp the concepts I needed to build this tool. Here's the link, again :) "Hands-On Guile Scheme for Beginners"

-]]>
- https://glenneth.org/content/posts/2024-09-24-scheme-journey.html - https://glenneth.org/content/posts/2024-09-24-scheme-journey.html - Tue, 24 Sep 2024 06:30:00 GMT - Glenn Thompson - personal, tech, guile, scheme, gnu, development -
- - - A Journey Through GNU Guix: From Installation to Returning to Arch Linux - As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey was insightful, filled with learning experiences, but ultimately led me back to the reliable shores of Arch. Here's a detailed account of my venture into GNU Guix, adding non-GNU channels, dealing with Nvidia drivers, running SwayWM, and the eventual retreat to Arch. - A Journey Through GNU Guix: From Installation to Returning to Arch Linux -

As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey was insightful, filled with learning experiences, but ultimately led me back to the reliable shores of Arch. Here's a detailed account of my venture into GNU Guix, adding non-GNU channels, dealing with Nvidia drivers, running SwayWM, and the eventual retreat to Arch.

-

Installation of GNU Guix

-

The installation process of GNU Guix was straightforward, thanks to the well-documented guide provided on their official website. Here's a quick rundown of the steps I followed:

-
    -
  1. Downloading the Installation Image: I started by downloading the latest ISO image from the GNU Guix website.
  2. -
  3. Creating a Bootable USB: Using dd, I created a bootable USB stick to install GNU Guix on my system.
  4. -
  5. Booting into the Installer: Booting from the USB was smooth, and I was greeted with the GNU Guix installer. The installer's simplicity reminded me of early days with Arch, where a minimalistic approach is preferred.
  6. -
  7. Partitioning and Setting Up File Systems: I partitioned my drive using fdisk and set up my file systems. I opted for ext4 for simplicity.
  8. -
  9. Configuring the System: Following the partition setup, I proceeded to configure my system by selecting the required packages and services. I decided to go with the Sway window manager as it's my preferred choice on Arch.
  10. -
-

System Configuration

-

During the installation process a window appears informing you that the config.scm file is located at /etc/config.scm. The first time I installed gnu guix on my work laptop I missed this message (pilot error) and I had to ask in the System Crafters IRC channel at irc.libera.chat, #systemcrafters. Come and join. It's a great place to be and the community there are an absolute treasure. Use your favourite IRC client or join through the webchat here. We would be glad to see you. Tell them glenneth sent you :).

-

My point is, I missed some vital information, so to the guix manual online it was. This can be found here. This link will take you to the dev version of the manual. Something else they don't tell you. This version has a little more detail than the standard manual, and I believe details extra features and may even be a little more up to date.

-

Adding Non-GNU Channels

-

One of the standout features of GNU Guix is the ability to add non-GNU channels to access a wider array of software packages. Here's how I did it:

-
    -
  1. Editing Channels: I edited the ~/.config/guix/channels.scm file to include non-GNU channels.
    (cons* (channel
    -        (name 'non-gnu)
    -        (url "https://example.com/non-gnu-channel.git"))
    -       %default-channels)
    -
    -
  2. -
  3. Updating Channels: Running guix pull updated my system to include packages from the non-GNU channel.
  4. -
-

Installing Nvidia Drivers

-

Being a gamer and someone who requires GPU acceleration for certain tasks, Nvidia drivers were a must. Here's the process I followed:

-
    -
  1. Adding Nvidia Channel: Added a channel that includes Nvidia drivers.
  2. -
  3. Installing Drivers: Installed the drivers using guix package -i nvidia-driver.
  4. -
  5. Configuring the System: I had to manually configure Xorg to use the Nvidia drivers, which involved editing the Xorg configuration files.
  6. -
-

Creating My Home Environment

-

To personalize my setup further, I used guix home import to create my own home environment and add packages. This allowed me to have a consistent environment across different machines. I also edited the config.scm file to include the latest Linux kernels and Nvidia drivers.

-

Additionally, I used the syncthing home-service-type in my home-configuration.scm file to install and configure Syncthing. This setup ensured my files were always in sync across devices, which is crucial for my workflow.

-

GNOME

-

All was good and I had a solid desktop environment running, even though it was gnome desktop. I had never used gnome, and I am more at home with a keyboard driven workflow. I had come from hyprland on Arch and wanted to get back to that workflow. The option I was presented with, in order to continue using wayland, pipewire etc. was SwayWM.

-

Sway

-

Installing SwayWM and it's dependencies and nice to haves was relatively straightforward. add the required packages, sway, swaybg, swayidle, swaylock, to my home-configuration.scm gile and run guix home reconfigure easy! The packages were installed and we were good to go.

-

The first issue I encountered was that sway does not run with the proprietary nvidia drivers, this was on the work laptop. I could get it to run but only after adding the --unsupported-gpu flag to exec sway. Lo and behold, we had a default sway window manager running.

-

Challenges with SwayWM and SMB Shares

-

With the system set up, I ran into a major roadblock: accessing SMB shares in a file manager while running SwayWM.

-
    -
  1. Thunar and GNOME Files: Neither Thunar nor the GNOME Files application could access SMB shares. This was crucial for my workflow as I frequently access network shares.
  2. -
  3. Troubleshooting: I tried various solutions, including installing additional packages and tweaking configurations, but nothing seemed to work.
  4. -
  5. Community Support: I reached out to the GNU Guix community for help. While they were supportive, the solutions provided didn't resolve my issues.
  6. -
-

To ensure that the problem was not hardware-related, I went out and purchased a Lenovo ThinkPad E16 Gen 1. I upgraded the RAM to 48GB and installed a Lenovo 2TB SSD to make it my personal laptop. However, even on this new setup, I faced the same issues accessing SMB shares and some networking services just wouldn't work.

-

I tried deleting the gdm login manager in my system configuration file, but after rebooting it was still showing the gnome login window. This was after reading somewhere online that sway was not on friendly terms with the gdm login manager.

-

Returning to Arch Linux

-

After several days of troubleshooting and not being able to access my SMB shares reliably, I made the difficult decision to revert to Arch Linux. The steps were:

-
    -
  1. Reinstalling Arch: I reinstalled Arch Linux using my tried-and-tested setup process.
  2. -
  3. Configuring SwayWM: Set up SwayWM and ensured all my applications were running smoothly.
  4. -
  5. Accessing SMB Shares: Accessing SMB shares was seamless, just as it was before my experiment with GNU Guix.
  6. -
-

Conclusion

-

I am still running GNU guix on the work laptop, I had to cave on my personal laptop and revert to Arch. My journey with GNU Guix was both enlightening and challenging. While I appreciate the functional package management and the philosophy behind GNU Guix, certain practical issues, like accessing SMB shares, were deal-breakers for my workflow. Arch Linux continues to be my go-to distribution, providing the flexibility and reliability I need for my daily tasks. So, at the moment I am using my personal laptop for work and still trying to figure out the issues I am having on my work laptop. But, to be honest, I prefer working on the thinkpad over working on the MSI laptop that work handed out :).

-

If you're an enthusiast looking to explore new package management paradigms, I highly recommend giving GNU Guix a try. Just be prepared for a few hiccups along the way, and always have a backup plan!

-
-

Feel free to share your thoughts and experiences with GNU Guix or any other distributions you've tried. Let's keep the conversation going!

-

Shameless plug

-

Go here to find all the ways you can engage with the SystemCrafters community. It's a great place to hang out and discuss all thing craftery. You will also notice the Craftering ring that I am a part of. Click the links and see blogs by some of the community members. Always interesting to read what other Crafters are up to.

-

Thanks for taking the time to read my blog post. It is greatly appreciated, and I hope you come back.

-

Happy Hacking!!

-]]>
- https://glenneth.org/content/posts/2024-07-26-gnu-guix-journey.html - https://glenneth.org/content/posts/2024-07-26-gnu-guix-journey.html - Fri, 26 Jul 2024 07:30:00 GMT - Glenn Thompson - personal, tech, gnu, guix, swaywm, nvidia -
- - - Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix - Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation. - Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix -

Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation.

-

Discovering Scheme with System Crafters

-

My journey began with a desire to dive deeper into programming languages and their ecosystems. I am a member of the System Crafters Community, and its founder, David Wilson, announced a short four week course as an introduction to Guile Scheme. The course, Hands-On Guile Scheme for Beginners, provided me with a robust introduction to Guile Scheme, a language that emphasizes simplicity and elegance. David's clear explanations and practical examples made learning Scheme both engaging and approachable.

-

The Move to GNU Guix

-

Inspired by the principles of Scheme, I decided to take a leap further into the open-source world by transitioning from Arch Linux to GNU Guix. The Guix community, particularly the folks in the #systemcrafters channel on irc.libera.chat, were incredibly supportive and instrumental in helping me navigate this new environment. Their guidance made the switch smooth and rewarding, reinforcing the power and flexibility of GNU Guix as a functional package manager and operating system. More about that experience in another post.

-

There are too many individuals to name here that have helped with the installation and configuration on Gnu guix to mention here. You all have been an incredible help for which I am extremely grateful. Thank you all , for enduring my ignorance, and for your patience and your help.

-

From Hugo to Haunt

-

As I settled into Guix, I faced a challenge: Hugo, the static site generator I previously used, was not available as a Guix package. This led me to explore alternatives and eventually discover Haunt, a Scheme-based static site generator that aligns perfectly with my newfound appreciation for Scheme and Guix.

-

Overcoming Challenges with Haunt

-

Transitioning to Haunt wasn't without its challenges. There are no readily available templating systems available for haunt like there are for hugo, but there are plenty of examples here. One of my own primary difficulties was creating a custom template that matched my site's aesthetic requirements and functionality needs. Initially, I struggled with configuring the theme layout and ensuring the CSS was applied correctly. Another hurdle was generating the correct URLs for posts and ensuring that summaries appeared as intended on the front page.

-

Thankfully, the Haunt manual proved to be an invaluable resource throughout this process. The comprehensive documentation provided clear guidance on using various modules, functions, and procedures. By carefully studying the examples and explanations, I was able to overcome the obstacles and achieve the desired results for my site. The manual's detailed descriptions of Haunt's inner workings were particularly helpful in understanding how to leverage the flexibility of Scheme to customize my blog.

-

Crafting My Own Template

-

Moving from Hugo to Haunt required me to create my own template and customize my site's appearance. This was an exciting opportunity to apply the skills I had learned from David's course and experiment with Scheme in a practical context.

-

Creating the Template

-

Haunt's flexibility allowed me to define my own theme layout and structure. Here's a snippet of my haunt.scm file, where I defined the theme layout and added custom footer content:

-
(use-modules (haunt asset)
-             (haunt builder blog)
-             (haunt builder atom)
-             (haunt builder assets)
-             (haunt reader commonmark)
-             (haunt site)
-             (haunt post)
-             (sxml simple)    ; For HTML generation
-             (srfi srfi-1)
-             (srfi srfi-19))  ; For date and time procedures
-
-;; Load custom templates
-(load "templates/post.scm")
-
-(define (format-date date)
-  (date->string date "~Y-~m-~d"))
-
-;; Define a function to generate the URL for a post
-(define (post-url post)
-  (string-append "/" (post-slug post) ".html"))
-
-;; Define a function to extract a summary from the post content
-(define (post-summary post)
-  (let ((content (post-sxml post)))
-    (if (null? content)
-        ""
-        (let ((first-paragraph (car content)))
-          (if (string? first-paragraph)
-              (substring first-paragraph 0 (min 200 (string-length first-paragraph)))
-              (sxml->string first-paragraph))))))
-
-;; Define the theme layout
-(define (theme-layout site title content)
-  (let ((current-year (number->string (date-year (current-date)))))
-    `(html
-      (head
-       (meta (@ (charset "utf-8")))
-       (meta (@ (name "viewport") (content "width=device-width, initial-scale=1.0, shrink-to-fit=no")))
-       (link (@ (rel "stylesheet") (href "/assets/palenight.css")))
-       (style
-        " .craftering {
-            margin: auto;
-            width: 50%;
-            text-align: center;
-        }
-        .webring-text {
-            text-align: center;
-            margin-bottom: 20px;
-            color: white;
-        }
-        .craftering a {
-            color: #dddddd;
-        }
-        .webring-text a {
-            color: #dddddd;
-        }")
-       (title ,title))
-      (body
-       (header (h1 ,(site-title site)))
-       (main ,content)
-       (footer (@ (class "bg-black bottom-0 w-100 pa3") (role "contentinfo"))
-               (div (@ (class "flex justify-between"))
-                    (div (@ (class "webring-text"))
-                         (p "I am part of the " (a (@ (href "https://systemcrafters.net") (target "_blank")) "System Crafters") " webring:"))
-                    (div (@ (class "craftering"))
-                         (a (@ (href "https://craftering.systemcrafters.net/@glenneth/previous")) "←")
-                         (a (@ (href "https://craftering.systemcrafters.net/")) "craftering")
-                         (a (@ (href "https://craftering.systemcrafters.net/@glenneth/next")) "→"))))))))
-
-;; Define the custom theme with a consistent layout for index
-(define my-theme
-  (theme #:name "My Custom Theme"
-         #:layout theme-layout
-         #:post-template post-template
-         #:collection-template
-         (lambda (site title posts prefix)
-           `(div (@ (class "content"))
-              (h2 ,title)
-              (ul
-                ,@(map (lambda (post)
-                         `(li
-                            (article
-                              (header
-                               (h3 (a (@ (href ,(post-url post))) ,(post-title post))))
-                              (p ,(format-date (post-date post)))
-                              (p ,(post-summary post))
-                              (p (a (@ (href ,(post-url post))) "Read more...")))))
-                       posts))))))
-
-;; Site configuration
-(site #:title "Just Another Personal Blog"
-      #:domain "glenneth.srht.site"
-      #:default-metadata
-      '((author . "Glenn Thompson")
-        (email  . "glenn@kirstol.org"))
-      #:readers (list commonmark-reader)
-      #:builders (list
-                  (blog #:theme my-theme)
-                  (atom-feed)
-                  (atom-feeds-by-tag)
-                  (static-directory "images")
-                  (static-directory "assets")))
-
-

Customizing the CSS

-

To give my site a personalized touch, I crafted a CSS stylesheet that matched my aesthetic preferences. Here’s an excerpt from my palenight.css file:

-
body {
-  display: flex;
-  justify-content: center;
-  padding: 10px;
-}
-
-.content, header, footer, main {
-  max-width: 90%;
-  padding: 0 5%;
-}
-
-header {
-  text-align: center;
-  margin-bottom: 20px;
-}
-
-footer {
-  text-align: center;
-  margin-top: 20px;
-}
-
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-
-li {
-  margin-bottom: 20px;
-}
-
-a {
-  text-decoration: none;
-}
-
-a:hover {
-  text-decoration: underline;
-}
-
-body {
-  background-color: #292d3e;
-  color: #d0d0d0;
-}
-
-a {
-  color: #82aaff;
-}
-
-h1, h2, h3, h4, h5, h6 {
-  color: #c792ea;
-}
-
-.content {
-  background-color: #1e1e2e;
-  padding: 20px;
-  border-radius: 5px;
-}
-
-article {
-  background-color: #282a36;
-  padding: 15px;
-  border-radius: 8px;
-  margin-bottom: 20px;
-}
-
-article header {
-  margin-bottom: 10px;
-}
-
-.date {
-  color: #6272a4;
-  font-size: 0.9em;
-}
-
-/* Additional styles for the craftering */
-.craftering {
-  margin: auto;
-  width: 50%;
-  text-align: center;
-}
-
-.webring-text {
-  text-align: center;
-  margin-bottom: 20px;
-  color: white;
-}
-
-.craftering a {
-  color: #dddddd;
-}
-
-.webring-text a {
-  color: #dddddd;
-}
-
-/* Additions for mobile device readability */
-
-meta {
-  name: viewport;
-  content: width=device-width, initial-scale=1, shrink-to-fit=no;
-}
-
-@media screen and (max-width: 767px) {
-  /* Customize styles for smaller screens */
-  .logo {
-    max-width: 200px;
-  }
-
-}
-
-

I use the doom-palenight theme in Emacs, my preferred text editor, and I wanted my site to match that aesthetic.

-

Publishing with Haunt and Hut

-

In addition to using Haunt, I adopted hut, a set of command-line tools for interacting with SourceHut, to publish my blog. This streamlined my workflow, making it easier to manage and deploy my site directly from my local environment.

-

Conclusion

-

Transitioning from Hugo to Haunt, learning Scheme, and embracing GNU Guix has been an enriching experience. It's not just about using new tools; it's about joining a community that values simplicity, transparency, and collaboration. If you're curious about Scheme or GNU Guix, I highly recommend checking out David Wilson's course on System Crafters and joining the discussions on IRC.

-

I am not a developer of any kind, and learning Scheme has opened my eyes as to how I can craft an environment that I want to work in, and not endure a working environment that the computer is forcing upon me.

-

Thank you for reading, and stay tuned for more updates on my journey!

-]]>
- https://glenneth.org/content/posts/2024-05-15-hugo-to-haunt.html - https://glenneth.org/content/posts/2024-05-15-hugo-to-haunt.html - Wed, 15 May 2024 07:30:00 GMT - Glenn Thompson - personal, tech, keyboards, glove80 -
- - - A Rollercoaster Week: From Amman to Newcastle, and back again - The Journey Begins - Two weeks ago was a whirlwind of events, taking me from the conforting embrace of Amman, Jordan to the vibrant streets of Newcastle, England. It was a journey filled with highs and lows, professional achievements, and personal challenges.

-

The Journey Begins

-

It all started on a Monday morning in Amman as I embarked on a journey to attend a Quality Control (QC) conference in Newcastle. The anticipation of presenting my work at an international forum filled me with excitement and nerves. The conference was scheduled for just one day, but the impact it had on me would last much longer.

-

A Successful Presentation

-

Tuesday arrived, and with it came the day of the conference. Armed with a PowerPoint presentation comprising over 130 slides, I delved into four hours of intense presenting. Despite the pressure, the conference was a resounding success. My project received positive feedback, and I felt a sense of accomplishment as I shared my work with colleagues from around the world.

-

The Toll of Travel

-

However, as I returned to Amman on Wednesday, I couldn't shake off a sense of exhaustion. Little did I know that the toll of travel would soon manifest itself in a most unexpected manner.

-

Thursday morning greeted me with heavy flu-like symptoms. It hit me like a ton of bricks. The combination of jet lag, long hours of presenting, and exposure to new environments had taken its toll on my immune system. I was bedridden, grappling with a chesty cough that seemed relentless.

-

The Show Must Go On

-

Despite my illness, there was no time for rest. The following week demanded my presence at a site meeting where I was tasked with condensing my extensive slide deck into a concise presentation of just 12 slides. The challenge was daunting, but I tackled it with determination.

-

Reflecting on the Journey

-

As I look back on the rollercoaster week that was, I'm struck by the juxtaposition of success and struggle. From the heights of presenting at an international conference to the lows of battling illness, it was a journey that tested my resilience and resolve.

-

But through it all, one thing remains clear: adversity only serves to make us stronger. Each obstacle we overcome, whether professional or personal, contributes to our growth and development.

-

So here's to the rollercoaster weeks, the ones filled with ups and downs, twists and turns. For it is in those moments of challenge that we discover the true extent of our capabilities.

-

As I upload this blog post using Hugo, I do so with a renewed sense of gratitude for the journey and all it has taught me. Here's to embracing the ride, wherever it may take us.

-]]>
- https://glenneth.org/content/posts/2024-05-01-amman-newcastle-journey.html - https://glenneth.org/content/posts/2024-05-01-amman-newcastle-journey.html - Wed, 01 May 2024 14:40:58 GMT - Glenn Thompson - work, travel -
-
+ + + + Glenn Thompson's Blog + Personal blog about programming, technology, and other interests + https://glenneth.org + + en-us + Sun, 28 Sep 2025 08:21:15 GMT + + + Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow + "Six months after my comprehensive development environment overview, I share the significant evolution to Guix Home and enhanced Emacs configurations that have transformed my daily workflow." + Introduction +

Six months ago, I shared a detailed look at my development environment in 2025, covering my hybrid approach with ArcoLinux, Guix package management, and Emacs-centered workflow. Since then, my setup has undergone a significant evolution driven by both choice and necessity.

+

The most significant change has been a transition to WSL2 on Windows 11 for my work environment, necessitated by corporate requirements. Rather than seeing this as a limitation, I've embraced it as an opportunity to refine my development approach, adopting Guix Home for complete environment management and building a custom Emacs installation from the master branch.

+

This evolution has taught me valuable lessons about adaptability and the power of declarative configuration in maintaining consistency across different underlying systems.

+

The Guix Home Revolution

+

From Hybrid to Unified

+

In March, I described my hybrid approach using both pacman/AUR and Guix for different aspects of my system. While this worked well, I found myself constantly managing the boundary between system and user packages, dealing with occasional conflicts, and maintaining separate configuration files.

+

Guix Home changed everything. Now I can declaratively manage:

+
    +
  • All my development tools and applications
  • +
  • Shell configuration and environment variables
  • +
  • Dotfiles and configuration files
  • +
  • Services and background processes
  • +
  • Desktop environment customizations
  • +
+

Current Guix Home Configuration

+

My home-configuration.scm has become the single source of truth for my development environment, particularly focused on Scheme/Guile development:

+
;; Guix Home configuration for Glenn's Scheme development environment
+
+(use-modules (gnu home)
+             (gnu packages)
+             (gnu services)
+             (gnu home services)
+             (gnu home services shells)
+             (gnu home services guix)
+             (gnu home services mcron)
+             (guix gexp))
+
+(home-environment
+  ;; Packages to install in the home environment
+  (packages (specifications->packages 
+             '(;; System essentials
+               "glibc-locales"
+               
+               ;; Scheme/Guile development environment
+               "guile-next"        ; Latest Guile development version
+               "guile-hoot"        ; Scheme to WebAssembly compiler
+               "guile-goblins"     ; Distributed programming environment
+               "guile-lib"         ; Useful Guile libraries
+               "guile-reader"      ; Reader extensions for Guile
+               "guile-json"        ; JSON support for Guile
+               
+               ;; Development tools  
+               ;; Note: Using custom-built Emacs 31.0.50 installation
+               "git"               ; Version control
+               "make"              ; Build system
+               "gcc-toolchain"     ; C compiler and tools
+               "pkg-config"        ; Package configuration
+               "texinfo"           ; Documentation system
+               "rlwrap")))         ; Readline wrapper for better REPL experience
+
+  ;; Services for the home environment
+  (services
+   (list
+    ;; Set up environment variables for Scheme development
+    (simple-service 'scheme-dev-env-vars
+                    home-environment-variables-service-type
+                    '(("EDITOR" . "emacs")
+                      ("GUILE_LOAD_PATH" . "$HOME/.guix-home/profile/share/guile/site/3.0:$GUILE_LOAD_PATH")
+                      ("GUILE_LOAD_COMPILED_PATH" . "$HOME/.guix-home/profile/lib/guile/3.0/site-ccache:$GUILE_LOAD_COMPILED_PATH")
+                      ("GUIX_LOCPATH" . "$HOME/.guix-home/profile/lib/locale")
+                      ("GUILE_AUTO_COMPILE" . "1")
+                      ("GUILE_WARN_DEPRECATED" . "detailed")))
+
+    ;; Add a simple mcron job for keeping system updated
+    (simple-service 'update-reminder
+                    home-mcron-service-type
+                    (list #~(job "0 12 * * 0"  ; Every Sunday at noon
+                                "echo 'Consider running: guix pull && guix home reconfigure ~/.config/guix/home-configuration.scm'"))))))
+
+

Benefits Realized

+

The transition to Guix Home has delivered on its promises:

+

Complete Reproducibility: I can now recreate my entire user environment on any machine with a single command: guix home reconfigure home-configuration.scm

+

Atomic Updates: Changes to my environment are atomic - either they work completely or roll back cleanly. No more broken states from partial updates.

+

Version Control Everything: My entire environment configuration lives in Git, with meaningful commit messages tracking every change to my setup.

+

Effortless Rollbacks: When an update breaks something, guix home roll-back instantly restores the previous working state.

+

Dependency Isolation: Each application gets exactly the dependencies it needs, eliminating conflicts between different tools requiring different library versions.

+

Enhanced Emacs Workflow

+

Custom Emacs Build from Master

+

One of the most significant changes in my setup has been building Emacs from the master branch rather than relying on distribution packages. This decision was driven by several factors:

+
    +
  • Latest Features: Access to cutting-edge features and improvements before they reach stable releases
  • +
  • WSL2 Optimization: Better integration with the WSL2 environment through custom compilation flags
  • +
  • Performance Tuning: Ability to optimize the build for my specific use case and hardware
  • +
+

Building Emacs 31.0.50 from source on WSL2 Ubuntu has given me a more responsive and feature-rich editing environment, particularly for Scheme development where the latest improvements in language support make a noticeable difference.

+

Configuration Management Evolution

+

While I was already using Emacs extensively in March, my configuration approach has matured significantly. I've moved from a monolithic configuration to a modular, feature-based system that's easier to maintain and debug.

+

New Emacs Enhancements

+

Improved LSP Integration: My language server setup now provides more consistent and reliable code intelligence across all my projects.

+

Enhanced Org Mode Workflow: I've integrated Org mode more deeply into my daily workflow for:

+
    +
  • Project planning and tracking
  • +
  • Meeting notes and documentation
  • +
  • Time tracking and productivity analysis
  • +
  • Knowledge management and linking
  • +
+

Better Terminal Integration: Using vterm and multi-vterm, I now have seamless terminal integration within Emacs, reducing context switching.

+

Refined Completion System: My completion setup with Vertico, Consult, and Marginalia has been fine-tuned for faster, more intuitive navigation.

+

Development Workflow Improvements

+

Project Management: Using projectile with enhanced project templates and automated setup scripts.

+

Code Quality: Integrated formatting, linting, and testing directly into my editing workflow with immediate feedback.

+

Documentation: Streamlined documentation generation and maintenance using Org mode's export capabilities.

+

Workflow Integration Benefits

+

Seamless Environment Switching

+

With Guix Home managing my entire environment, switching between different project contexts has become effortless. Each project can specify its exact dependencies, and Guix ensures they're available without affecting other projects.

+

Consistent Across Machines

+

Whether I'm working on my desktop, laptop, or a remote server, my environment is identical. This consistency has eliminated the "works on my machine" problem entirely.

+

Simplified Onboarding

+

Setting up a new development machine now takes minutes instead of hours. Clone my configuration repository, run guix home reconfigure, and everything is ready.

+

Challenges and Solutions

+

Learning Curve

+

Challenge: Guix Home's declarative approach required rethinking how I manage my environment.

+

Solution: Incremental migration, starting with simple configurations and gradually adding complexity as I became more comfortable with the system.

+

Documentation Gaps

+

Challenge: Guix Home is relatively new, with fewer examples and tutorials compared to traditional dotfile management.

+

Solution: Active participation in the Guix community, reading source code, and documenting my own discoveries.

+

Integration Complexity

+

Challenge: Some applications required custom integration work to play nicely with Guix Home.

+

Solution: Creating custom service definitions and contributing them back to the community when possible.

+

Performance and Productivity Impact

+

The move to Guix Home has had measurable impacts on my productivity:

+
    +
  • Reduced Setup Time: New project environments spin up in seconds
  • +
  • Fewer Context Switches: Everything I need is consistently available
  • +
  • Less Debugging: Reproducible environments mean fewer environment-related issues
  • +
  • Improved Focus: Less time managing tools means more time creating
  • +
+

Future Directions

+

Looking ahead, I'm exploring:

+

Custom Guix Channels: Creating personal channels for specialized tools and configurations not yet in the main Guix repository.

+

Advanced Service Integration: Developing more sophisticated service definitions for complex development workflows.

+

Cross-Machine Synchronization: Using Guix Home with remote development servers and cloud environments.

+

Community Contributions: Sharing useful service definitions and configurations with the broader Guix community.

+

Lessons Learned

+

Embrace Gradual Migration

+

Don't try to convert everything at once. Start with core tools and gradually expand your Guix Home configuration as you become more comfortable with the system.

+

Document Everything

+

Keep detailed notes about your configuration choices. The declarative nature of Guix Home makes it easy to forget why you made certain decisions.

+

Engage with the Community

+

The Guix community is incredibly helpful and knowledgeable. Don't hesitate to ask questions and share your experiences.

+

Version Control is Essential

+

Treat your Guix Home configuration like any other important code - use meaningful commit messages, create branches for experiments, and maintain good version control hygiene.

+

Conclusion

+

The evolution from my March setup to the current Guix Home-based environment represents more than just a tool change - it's a fundamental shift in how I think about development environment management. The move from imperative to declarative configuration has brought a level of reliability and reproducibility that has transformed my daily workflow.

+

For anyone considering similar changes, I'd recommend starting small and gradually expanding your declarative configuration. The initial learning curve is worth the long-term benefits of having a truly reproducible, version-controlled development environment.

+

The combination of Guix Home for environment management and a refined Emacs configuration has created a development setup that feels both powerful and effortless. It's a foundation I'm confident will serve me well as my projects and requirements continue to evolve.

+

What aspects of environment management do you find most challenging? Have you experimented with declarative configuration approaches? I'd love to hear about your experiences and any questions you might have about making similar transitions.

+]]>
+ https://glenneth.org/content/posts/2025-09-28-dev-environment-evolution-guix-home.html + https://glenneth.org/content/posts/2025-09-28-dev-environment-evolution-guix-home.html + Invalid Date + Glenn Thompson + ["development", "guix", "guix-home", "emacs", "workflow", "productivity", "evolution"] +
+
\ No newline at end of file diff --git a/index.html b/index.html index afdf9ad..9d1fd43 100644 --- a/index.html +++ b/index.html @@ -58,197 +58,216 @@

Blog Posts

-
- -
-
- Tech - communitywebringsystemcraftersreflection - - -
-

- - One Year of Craftering: Building Connections in the System Crafters Community - -

-

Next Thursday, 03-APR-2025, marks the first anniversary of the Craftering webring, a vibrant community initiative started by shom that connects personal websites and blogs within the System Crafters c...

-
- communitywebringsystemcraftersreflection -
-
- - -
-
- Tech - webdevelopmentjavascriptstatic-sitelessons - - -
-

- - Lessons Learned: One Year with a Custom Static Site Generator - -

-

It's been just over a year since I transitioned from Haunt to my own custom static site generator for this website. What started as an experiment to gain more control over my publishing workflow has e...

-
- webdevelopmentjavascriptstatic-sitelessons -
-
- - -
-
- Tech - developmentguixtoolsworkflowproductivityweb - - -
-

- - My Development Environment in 2025: From Editor to Deployment - -

-

The tools we use shape how we work. Over the years, my development environment has evolved alongside my technical journey through different programming languages, paradigms, and projects. This post of...

-
- developmentguixtoolsworkflowproductivityweb -
-
- - -
-
- Tech - webdevelopmentjavascriptstatic-sitehauntguilehugo - - -
-

- - From Hugo to Haunt to Custom: My Journey in Static Site Generation - -

-

My journey with static site generators has been one of continuous learning and evolution. It started with Hugo, transitioned through Haunt, and has now led me to build my own custom solution. Each ste...

-
- webdevelopmentjavascriptstatic-sitehauntguilehugo -
-
- - -
-
- Tech - techguileschemedevelopmentfunctional-programming - - -
-

- - Beyond Theory: Building Practical Tools with Guile Scheme - -

-

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world pro...

-
- techguileschemedevelopmentfunctional-programming -
-
- - -
-
- Tech - personaltechguileschemegnudevelopment - - -
-

- - A Journey into Scheme - -

-

I've spent my career as an electrical engineer, not a software developer. However, my recent journey in to GNU/Liniux required a tool for managing symlinks, and that's how I began learning Scheme—spec...

-
- personaltechguileschemegnudevelopment -
-
- - -
-
- Tech - personaltechgnuguixswaywmnvidia - - -
-

- - A Journey Through GNU Guix: From Installation to Returning to Arch Linux - -

-

As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey...

-
- personaltechgnuguixswaywmnvidia -
-
- - -
-
- Tech - personaltechkeyboardsglove80 - - -
-

- - Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix - -

-

Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation.

-
- personaltechkeyboardsglove80 -
-
- - -
-
- Tech - worktravel - - -
-

- - A Rollercoaster Week: From Amman to Newcastle, and back again - -

-

Two weeks ago was a whirlwind of events, taking me from the conforting embrace of Amman, Jordan to the vibrant streets of Newcastle, England. It was a journey filled with highs and lows, professional...

-
- worktravel -
-
- - -
-
- Tech - personaltechkeyboardsglove80 - - -
-

- - Aesthetic Meets Ergonomics: My Deep Dive into the Glove80 Keyboard - -

-

As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant...

-
- personaltechkeyboardsglove80 -
-
- +
+ +
+
+ Tech + developmentguixguix-homeemacsworkflowproductivityevolution + + +
+

+ + Development Environment Evolution: Embracing Guix Home and Enhanced Emacs Workflow + +

+

Six months ago, I shared a detailed look at my development environment in 2025, covering my hybrid approach with ArcoLinux, Guix package management, and Emacs-centered workflow. Since then, my setup h...

+
+ developmentguixguix-homeemacsworkflowproductivityevolution +
+
+ + +
+
+ Tech + communitywebringsystemcraftersreflection + + +
+

+ + One Year of Craftering: Building Connections in the System Crafters Community + +

+

Next Thursday, 03-APR-2025, marks the first anniversary of the Craftering webring, a vibrant community initiative started by shom that connects personal websites and blogs within the System Crafters c...

+
+ communitywebringsystemcraftersreflection +
+
+ + +
+
+ Tech + webdevelopmentjavascriptstatic-sitelessons + + +
+

+ + Lessons Learned: One Year with a Custom Static Site Generator + +

+

It's been just over a year since I transitioned from Haunt to my own custom static site generator for this website. What started as an experiment to gain more control over my publishing workflow has e...

+
+ webdevelopmentjavascriptstatic-sitelessons +
+
+ + +
+
+ Tech + developmentguixtoolsworkflowproductivityweb + + +
+

+ + My Development Environment in 2025: From Editor to Deployment + +

+

The tools we use shape how we work. Over the years, my development environment has evolved alongside my technical journey through different programming languages, paradigms, and projects. This post of...

+
+ developmentguixtoolsworkflowproductivityweb +
+
+ + +
+
+ Tech + webdevelopmentjavascriptstatic-sitehauntguilehugo + + +
+

+ + From Hugo to Haunt to Custom: My Journey in Static Site Generation + +

+

My journey with static site generators has been one of continuous learning and evolution. It started with Hugo, transitioned through Haunt, and has now led me to build my own custom solution. Each ste...

+
+ webdevelopmentjavascriptstatic-sitehauntguilehugo +
+
+ + +
+
+ Tech + techguileschemedevelopmentfunctional-programming + + +
+

+ + Beyond Theory: Building Practical Tools with Guile Scheme + +

+

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world pro...

+
+ techguileschemedevelopmentfunctional-programming +
+
+ + +
+
+ Tech + personaltechguileschemegnudevelopment + + +
+

+ + A Journey into Scheme + +

+

I've spent my career as an electrical engineer, not a software developer. However, my recent journey in to GNU/Liniux required a tool for managing symlinks, and that's how I began learning Scheme—spec...

+
+ personaltechguileschemegnudevelopment +
+
+ + +
+
+ Tech + personaltechgnuguixswaywmnvidia + + +
+

+ + A Journey Through GNU Guix: From Installation to Returning to Arch Linux + +

+

As a long-time user of Arch Linux, I decided to explore the world of GNU Guix to see if it could better suit my needs, especially with my growing interest in functional package management. The journey...

+
+ personaltechgnuguixswaywmnvidia +
+
+ + +
+
+ Tech + personaltechkeyboardsglove80 + + +
+

+ + Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix + +

+

Hello there! I'm Glenn Thompson, and today, I want to share a significant part of my recent journey into the world of Scheme, GNU Guix, and static site generation.

+
+ personaltechkeyboardsglove80 +
+
+ + +
+
+ Tech + worktravel + + +
+

+ + A Rollercoaster Week: From Amman to Newcastle, and back again + +

+

Two weeks ago was a whirlwind of events, taking me from the conforting embrace of Amman, Jordan to the vibrant streets of Newcastle, England. It was a journey filled with highs and lows, professional...

+
+ worktravel +
+
+ + +
+
+ Tech + personaltechkeyboardsglove80 + + +
+

+ + Aesthetic Meets Ergonomics: My Deep Dive into the Glove80 Keyboard + +

+

As my career trajectory veered from being an integral member of an electrical engineering team to assuming the role of Deputy Project Manager, the nature of my daily activities underwent a significant...

+
+ personaltechkeyboardsglove80 +
+
+
diff --git a/src/js/md-to-html.js b/src/js/md-to-html.js index 13326be..84b6f63 100644 --- a/src/js/md-to-html.js +++ b/src/js/md-to-html.js @@ -223,15 +223,28 @@ async function updateIndexWithSummaries() { // Extract metadata const metadata = {}; - content.replace(/^---\n([\s\S]*?)\n---\n/, (_, frontMatter) => { - frontMatter.split('\n').forEach(line => { - const [key, ...valueParts] = line.split(':'); - if (key && valueParts.length > 0) { - metadata[key.trim()] = valueParts.join(':').trim(); + // More flexible regex to handle different line endings + const frontMatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/); + if (frontMatterMatch) { + const frontMatter = frontMatterMatch[1]; + frontMatter.split(/\r?\n/).forEach(line => { + const colonIndex = line.indexOf(':'); + if (colonIndex > 0) { + const key = line.substring(0, colonIndex).trim(); + let value = line.substring(colonIndex + 1).trim(); + + // Remove quotes if present + if ((value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'"))) { + value = value.slice(1, -1); + } + + if (key && value) { + metadata[key] = value; + } } }); - return ''; - }); + } // Extract summary const summary = extractSummary(content); @@ -239,18 +252,45 @@ async function updateIndexWithSummaries() { // Parse and format the date let formattedDate = ''; let isoDate = ''; + + if (!metadata.date) { + console.warn(`No date found for ${file}`); + continue; + } + try { - // Handle date formats like "2024-04-08 16:50" or "2024-04-08" - const dateStr = metadata.date.split(' ')[0]; + let dateStr = ''; + + // Handle different date formats + if (typeof metadata.date === 'string') { + // String format: "2024-04-08 16:50" or "2024-04-08" + dateStr = metadata.date.split(' ')[0]; + } else if (typeof metadata.date === 'number') { + // Number format: 2025-04-02 (YAML parsed as number) + dateStr = metadata.date.toString(); + } else if (metadata.date instanceof Date) { + // Date object + dateStr = metadata.date.toISOString().split('T')[0]; + } else { + // Fallback: convert to string and extract date part + dateStr = String(metadata.date).split(' ')[0]; + } + const date = new Date(dateStr); - formattedDate = date.toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' - }); - isoDate = dateStr; + if (!isNaN(date.getTime())) { + formattedDate = date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + }); + isoDate = dateStr; + } else { + console.warn(`Invalid date format for ${file}: ${metadata.date} (type: ${typeof metadata.date})`); + continue; + } } catch (e) { console.error(`Error parsing date for ${file}:`, e); + continue; } // Parse tags diff --git a/website-deploy.zip b/website-deploy.zip index f436ae3859b3c4118baba836155aea414723097e..9d439a3e41f826e1d2123ac19babd4f9e3583008 100644 GIT binary patch delta 71456 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 delta 71708 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 exv#Ha{^$BdM*|yleS}%iPX+-1fH#DWKHy)@{FL