Add Practical Scheme blog post and fix og:url formatting

This commit is contained in:
glenneth1 2024-12-03 05:01:12 +03:00
parent c63a517b7f
commit 89151a9356
10 changed files with 1317 additions and 58 deletions

View File

@ -0,0 +1,273 @@
<!DOCTYPE html>
<html lang="en" class="bg-base-bg">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta property="og:title" content="Beyond Theory: Building Practical Tools with Guile Scheme">
<meta property="og:description" content="">
<meta property="og:url" content="https://glenneth.org/content/posts/2024-12-03-practical-scheme.html">
<title>Beyond Theory: Building Practical Tools with Guile Scheme - Glenn Thompson</title>
<link href="../../dist/styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Merriweather:wght@400;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
.prose-palenight {
--tw-prose-body: #bfc7d5;
--tw-prose-headings: #ffd580;
--tw-prose-links: #82aaff;
--tw-prose-code: #c792ea;
--tw-prose-pre-bg: #1b1e2b;
}
.prose h2 {
color: var(--tw-prose-headings);
font-family: Merriweather, serif;
font-weight: 700;
font-size: 1.5rem;
margin-top: 2rem;
margin-bottom: 1rem;
}
.prose p {
margin-bottom: 1rem;
line-height: 1.625;
}
.prose a {
color: var(--tw-prose-links);
text-decoration: none;
}
.prose a:hover {
color: #89ddff;
}
.prose code {
color: var(--tw-prose-code);
font-family: 'JetBrains Mono', monospace;
}
.prose pre {
background-color: var(--tw-prose-pre-bg);
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
margin-bottom: 1rem;
}
.prose ul, .prose ol {
margin-top: 0.5rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.prose ul {
list-style-type: disc;
}
.prose ol {
list-style-type: decimal;
}
</style>
</head>
<body class="bg-base-bg text-palenight-50">
<nav class="fixed w-full bg-base-darker/80 backdrop-blur-sm shadow-sm z-50 border-b border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<a href="/" class="flex items-center font-serif text-xl font-bold text-accent-purple">Glenn Thompson</a>
</div>
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<a href="/#about" class="nav-link text-accent-blue hover:text-accent-cyan">About</a>
<a href="/#blog" class="nav-link text-accent-blue hover:text-accent-cyan">Blog</a>
<a href="/#projects" class="nav-link text-accent-blue hover:text-accent-cyan">Projects</a>
</div>
</div>
</div>
</nav>
<main class="pt-24 pb-16 px-4">
<div class="max-w-4xl mx-auto">
<div class="content text-palenight-100 space-y-6">
<div class="flex items-center justify-between mb-8">
<a href="/" class="inline-flex items-center text-accent-blue hover:text-accent-cyan transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd" />
</svg>
Back to Home
</a>
<time datetime="2024-12-03 10:00" class="text-palenight-300">2024-12-03 10:00</time>
</div>
<header class="mb-8">
<h1 class="text-4xl font-serif font-bold text-accent-yellow">Beyond Theory: Building Practical Tools with Guile Scheme</h1>
<div class="flex items-center gap-4 text-palenight-300 mt-4">
<time datetime="2024-12-03 10:00">2024-12-03 10:00</time>
<span></span>
<span>5 min read</span>
<span></span>
<span>By Glenn Thompson</span>
</div>
</header>
<article class="prose prose-palenight max-w-none">
<h1>Beyond Theory: Building Practical Tools with Guile Scheme</h1>
<h2>Introduction</h2>
<p>A few months ago, I shared my journey into learning Scheme through building <code>stash</code>, a symlink manager. Since then, I&#39;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&#39;ve learned about building practical tools with Guile Scheme, sharing both successes and challenges along the way.</p>
<h2>The Power of Modular Design</h2>
<p>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&#39;s behavior. Here&#39;s how I structured <code>stash</code>:</p>
<pre><code class="language-scheme">(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
</code></pre>
<p>Each module has a specific responsibility:</p>
<ul>
<li><code>colors.scm</code>: Handles ANSI color formatting for terminal output</li>
<li><code>conflict.scm</code>: Manages conflict resolution when files already exist</li>
<li><code>file-ops.scm</code>: Handles file system operations</li>
<li><code>help.scm</code>: Provides usage information</li>
<li><code>log.scm</code>: Manages logging operations</li>
<li><code>paths.scm</code>: Handles path manipulation and normalization</li>
</ul>
<h2>Robust Path Handling</h2>
<p>One of the first challenges in building a file management tool is handling paths correctly. Here&#39;s how I approached it:</p>
<pre><code class="language-scheme">(define (expand-home path)
&quot;Expand ~ to the user&#39;s home directory.&quot;
(if (string-prefix? &quot;~&quot; path)
(string-append (getenv &quot;HOME&quot;) (substring path 1))
path))
(define (concat-path base path)
&quot;Concatenate two paths, ensuring there are no double slashes.&quot;
(if (string-suffix? &quot;/&quot; base)
(string-append (string-drop-right base 1) &quot;/&quot; path)
(string-append base &quot;/&quot; path)))
(define (ensure-config-path target-dir)
&quot;Ensure that the target directory has .config appended, avoiding double slashes.&quot;
(let ((target-dir (expand-home target-dir)))
(if (string-suffix? &quot;/&quot; target-dir)
(set! target-dir (string-drop-right target-dir 1)))
(if (not (string-suffix? &quot;/.config&quot; target-dir))
(string-append target-dir &quot;/.config&quot;)
target-dir)))
</code></pre>
<p>This approach ensures that:</p>
<ul>
<li>Home directory references (<code>~</code>) are properly expanded</li>
<li>Path concatenation doesn&#39;t create double slashes</li>
<li>Configuration paths are consistently structured</li>
</ul>
<h2>Interactive Conflict Resolution</h2>
<p>Real-world tools often need to handle conflicts. I implemented an interactive conflict resolution system:</p>
<pre><code class="language-scheme">(define (prompt-user-for-action)
&quot;Prompt the user to decide how to handle a conflict: overwrite (o), skip (s), or cancel (c).&quot;
(display (color-message
&quot;A conflict was detected. Choose action - Overwrite (o), Skip (s), or Cancel (c): &quot;
yellow-text))
(let ((response (read-line)))
(cond
((string-ci=? response &quot;o&quot;) &#39;overwrite)
((string-ci=? response &quot;s&quot;) &#39;skip)
((string-ci=? response &quot;c&quot;) &#39;cancel)
(else
(display &quot;Invalid input. Please try again.\n&quot;)
(prompt-user-for-action)))))
</code></pre>
<p>This provides a user-friendly interface for resolving conflicts while maintaining data safety.</p>
<h2>Logging for Debugging and Auditing</h2>
<p>Proper logging is crucial for debugging and auditing. I implemented a simple but effective logging system:</p>
<pre><code class="language-scheme">(define (current-timestamp)
&quot;Return the current date and time as a formatted string.&quot;
(let* ((time (current-time))
(seconds (time-second time)))
(strftime &quot;%Y-%m-%d-%H-%M-%S&quot; (localtime seconds))))
(define (log-action message)
&quot;Log an action with a timestamp to the stash.log file.&quot;
(let ((log-port (open-file &quot;stash.log&quot; &quot;a&quot;)))
(display (color-message
(string-append &quot;[&quot; (current-timestamp) &quot;] &quot; message)
green-text) log-port)
(newline log-port)
(close-port log-port)))
</code></pre>
<p>This logging system:</p>
<ul>
<li>Timestamps each action</li>
<li>Uses color coding for better readability</li>
<li>Maintains a persistent log file</li>
<li>Properly handles file operations</li>
</ul>
<h2>File Operations with Safety</h2>
<p>When dealing with file system operations, safety is paramount. Here&#39;s how I handle moving directories:</p>
<pre><code class="language-scheme">(define (move-source-to-target source-dir target-dir)
&quot;Move the entire source directory to the target directory, ensuring .config in the target path.&quot;
(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 &quot;Moved ~a to ~a\n&quot; source-dir target-source-dir))
(log-action (format #f &quot;Moved ~a to ~a&quot; source-dir target-source-dir))))
target-source-dir))
</code></pre>
<p>This implementation:</p>
<ul>
<li>Ensures paths are properly formatted</li>
<li>Creates necessary directories</li>
<li>Handles conflicts gracefully</li>
<li>Logs all operations</li>
<li>Returns the new path for further operations</li>
</ul>
<h2>Lessons Learned</h2>
<h3>What Worked Well</h3>
<ol>
<li><strong>Modular Design</strong>: Breaking the code into focused modules made it easier to maintain and test</li>
<li><strong>Functional Approach</strong>: Using pure functions where possible made the code more predictable</li>
<li><strong>Interactive Interface</strong>: Providing clear user prompts and colored output improved usability</li>
<li><strong>Robust Logging</strong>: Detailed logging helped with debugging and understanding program flow</li>
</ol>
<h3>Challenges Faced</h3>
<ol>
<li><strong>Path Handling</strong>: Dealing with different path formats and edge cases required careful attention</li>
<li><strong>Error States</strong>: Managing various error conditions while keeping the code clean</li>
<li><strong>User Interface</strong>: Balancing between automation and user control</li>
<li><strong>Documentation</strong>: Writing clear documentation that helps users understand the tool</li>
</ol>
<h2>Moving Forward</h2>
<p>Building <code>stash</code> 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.</p>
<h2>Resources</h2>
<ol>
<li><a href="https://www.gnu.org/software/guile/manual/">Guile Manual</a></li>
<li><a href="/content/posts/scheme-journey.html">My Previous Scheme Journey Post</a></li>
<li><a href="https://systemcrafters.net/community">System Crafters Community</a></li>
<li><a href="https://codeberg.org/glenneth/stash">Stash on Codeberg</a></li>
</ol>
<p>The code examples in this post are from my actual implementation of <code>stash</code>. Feel free to explore, use, and improve upon them!</p>
</article>
</div>
</div>
</main>
<footer class="bg-base-darker text-palenight-200 py-12 border-t border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center">
<p class="text-palenight-300">&copy; 2024 Glenn Thompson. All rights reserved.</p>
<div class="webring-text mt-6">
<p class="text-palenight-300">I am part of the <a href="https://systemcrafters.net" target="_blank" class="text-accent-blue hover:text-accent-cyan">System Crafters</a> webring:</p>
</div>
<div class="craftering mt-2 flex items-center justify-center gap-4 text-accent-blue">
<a href="https://craftering.systemcrafters.net/@glenneth/previous" class="hover:text-accent-cyan"></a>
<a href="https://craftering.systemcrafters.net/" class="hover:text-accent-cyan">craftering</a>
<a href="https://craftering.systemcrafters.net/@glenneth/next" class="hover:text-accent-cyan"></a>
</div>
<p class="text-palenight-300 mt-2">
<a href="mailto:glenn@glenneth.org" class="text-accent-blue hover:text-accent-cyan transition-colors">glenn@glenneth.org</a> |
<a href="https://glenneth.org" class="text-accent-blue hover:text-accent-cyan transition-colors">glenneth.org</a>
</p>
</div>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,171 @@
---
title: Beyond Theory: Building Practical Tools with Guile Scheme
author: Glenn Thompson
date: 2024-12-03 10:00
tags: tech, guile, scheme, development, functional-programming
---
# 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`:
```scheme
(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:
```scheme
(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:
```scheme
(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:
```scheme
(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:
```scheme
(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. **Functional Approach**: Using pure functions where possible made the code more predictable
3. **Interactive Interface**: Providing clear user prompts and colored output improved usability
4. **Robust Logging**: Detailed logging helped with debugging and understanding program flow
### Challenges Faced
1. **Path Handling**: Dealing with different path formats and edge cases required careful attention
2. **Error States**: Managing various error conditions while keeping the code clean
3. **User Interface**: Balancing between automation and user control
4. **Documentation**: Writing clear documentation that helps users understand the tool
## 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](https://www.gnu.org/software/guile/manual/)
2. [My Previous Scheme Journey Post](/content/posts/scheme-journey.html)
3. [System Crafters Community](https://systemcrafters.net/community)
4. [Stash on Codeberg](https://codeberg.org/glenneth/stash)
The code examples in this post are from my actual implementation of `stash`. Feel free to explore, use, and improve upon them!

View File

@ -0,0 +1,273 @@
<!DOCTYPE html>
<html lang="en" class="bg-base-bg">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta property="og:title" content="Beyond Theory: Building Practical Tools with Guile Scheme">
<meta property="og:description" content="">
<meta property="og:url" content="https://glenneth.org/content/posts/2024-12-03-practical-scheme.html">
<title>Beyond Theory: Building Practical Tools with Guile Scheme - Glenn Thompson</title>
<link href="../../dist/styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Merriweather:wght@400;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
.prose-palenight {
--tw-prose-body: #bfc7d5;
--tw-prose-headings: #ffd580;
--tw-prose-links: #82aaff;
--tw-prose-code: #c792ea;
--tw-prose-pre-bg: #1b1e2b;
}
.prose h2 {
color: var(--tw-prose-headings);
font-family: Merriweather, serif;
font-weight: 700;
font-size: 1.5rem;
margin-top: 2rem;
margin-bottom: 1rem;
}
.prose p {
margin-bottom: 1rem;
line-height: 1.625;
}
.prose a {
color: var(--tw-prose-links);
text-decoration: none;
}
.prose a:hover {
color: #89ddff;
}
.prose code {
color: var(--tw-prose-code);
font-family: 'JetBrains Mono', monospace;
}
.prose pre {
background-color: var(--tw-prose-pre-bg);
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
margin-bottom: 1rem;
}
.prose ul, .prose ol {
margin-top: 0.5rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.prose ul {
list-style-type: disc;
}
.prose ol {
list-style-type: decimal;
}
</style>
</head>
<body class="bg-base-bg text-palenight-50">
<nav class="fixed w-full bg-base-darker/80 backdrop-blur-sm shadow-sm z-50 border-b border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<a href="/" class="flex items-center font-serif text-xl font-bold text-accent-purple">Glenn Thompson</a>
</div>
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<a href="/#about" class="nav-link text-accent-blue hover:text-accent-cyan">About</a>
<a href="/#blog" class="nav-link text-accent-blue hover:text-accent-cyan">Blog</a>
<a href="/#projects" class="nav-link text-accent-blue hover:text-accent-cyan">Projects</a>
</div>
</div>
</div>
</nav>
<main class="pt-24 pb-16 px-4">
<div class="max-w-4xl mx-auto">
<div class="content text-palenight-100 space-y-6">
<div class="flex items-center justify-between mb-8">
<a href="/" class="inline-flex items-center text-accent-blue hover:text-accent-cyan transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd" />
</svg>
Back to Home
</a>
<time datetime="2024-12-03 10:00" class="text-palenight-300">2024-12-03 10:00</time>
</div>
<header class="mb-8">
<h1 class="text-4xl font-serif font-bold text-accent-yellow">Beyond Theory: Building Practical Tools with Guile Scheme</h1>
<div class="flex items-center gap-4 text-palenight-300 mt-4">
<time datetime="2024-12-03 10:00">2024-12-03 10:00</time>
<span></span>
<span>5 min read</span>
<span></span>
<span>By Glenn Thompson</span>
</div>
</header>
<article class="prose prose-palenight max-w-none">
<h1>Beyond Theory: Building Practical Tools with Guile Scheme</h1>
<h2>Introduction</h2>
<p>A few months ago, I shared my journey into learning Scheme through building <code>stash</code>, a symlink manager. Since then, I&#39;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&#39;ve learned about building practical tools with Guile Scheme, sharing both successes and challenges along the way.</p>
<h2>The Power of Modular Design</h2>
<p>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&#39;s behavior. Here&#39;s how I structured <code>stash</code>:</p>
<pre><code class="language-scheme">(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
</code></pre>
<p>Each module has a specific responsibility:</p>
<ul>
<li><code>colors.scm</code>: Handles ANSI color formatting for terminal output</li>
<li><code>conflict.scm</code>: Manages conflict resolution when files already exist</li>
<li><code>file-ops.scm</code>: Handles file system operations</li>
<li><code>help.scm</code>: Provides usage information</li>
<li><code>log.scm</code>: Manages logging operations</li>
<li><code>paths.scm</code>: Handles path manipulation and normalization</li>
</ul>
<h2>Robust Path Handling</h2>
<p>One of the first challenges in building a file management tool is handling paths correctly. Here&#39;s how I approached it:</p>
<pre><code class="language-scheme">(define (expand-home path)
&quot;Expand ~ to the user&#39;s home directory.&quot;
(if (string-prefix? &quot;~&quot; path)
(string-append (getenv &quot;HOME&quot;) (substring path 1))
path))
(define (concat-path base path)
&quot;Concatenate two paths, ensuring there are no double slashes.&quot;
(if (string-suffix? &quot;/&quot; base)
(string-append (string-drop-right base 1) &quot;/&quot; path)
(string-append base &quot;/&quot; path)))
(define (ensure-config-path target-dir)
&quot;Ensure that the target directory has .config appended, avoiding double slashes.&quot;
(let ((target-dir (expand-home target-dir)))
(if (string-suffix? &quot;/&quot; target-dir)
(set! target-dir (string-drop-right target-dir 1)))
(if (not (string-suffix? &quot;/.config&quot; target-dir))
(string-append target-dir &quot;/.config&quot;)
target-dir)))
</code></pre>
<p>This approach ensures that:</p>
<ul>
<li>Home directory references (<code>~</code>) are properly expanded</li>
<li>Path concatenation doesn&#39;t create double slashes</li>
<li>Configuration paths are consistently structured</li>
</ul>
<h2>Interactive Conflict Resolution</h2>
<p>Real-world tools often need to handle conflicts. I implemented an interactive conflict resolution system:</p>
<pre><code class="language-scheme">(define (prompt-user-for-action)
&quot;Prompt the user to decide how to handle a conflict: overwrite (o), skip (s), or cancel (c).&quot;
(display (color-message
&quot;A conflict was detected. Choose action - Overwrite (o), Skip (s), or Cancel (c): &quot;
yellow-text))
(let ((response (read-line)))
(cond
((string-ci=? response &quot;o&quot;) &#39;overwrite)
((string-ci=? response &quot;s&quot;) &#39;skip)
((string-ci=? response &quot;c&quot;) &#39;cancel)
(else
(display &quot;Invalid input. Please try again.\n&quot;)
(prompt-user-for-action)))))
</code></pre>
<p>This provides a user-friendly interface for resolving conflicts while maintaining data safety.</p>
<h2>Logging for Debugging and Auditing</h2>
<p>Proper logging is crucial for debugging and auditing. I implemented a simple but effective logging system:</p>
<pre><code class="language-scheme">(define (current-timestamp)
&quot;Return the current date and time as a formatted string.&quot;
(let* ((time (current-time))
(seconds (time-second time)))
(strftime &quot;%Y-%m-%d-%H-%M-%S&quot; (localtime seconds))))
(define (log-action message)
&quot;Log an action with a timestamp to the stash.log file.&quot;
(let ((log-port (open-file &quot;stash.log&quot; &quot;a&quot;)))
(display (color-message
(string-append &quot;[&quot; (current-timestamp) &quot;] &quot; message)
green-text) log-port)
(newline log-port)
(close-port log-port)))
</code></pre>
<p>This logging system:</p>
<ul>
<li>Timestamps each action</li>
<li>Uses color coding for better readability</li>
<li>Maintains a persistent log file</li>
<li>Properly handles file operations</li>
</ul>
<h2>File Operations with Safety</h2>
<p>When dealing with file system operations, safety is paramount. Here&#39;s how I handle moving directories:</p>
<pre><code class="language-scheme">(define (move-source-to-target source-dir target-dir)
&quot;Move the entire source directory to the target directory, ensuring .config in the target path.&quot;
(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 &quot;Moved ~a to ~a\n&quot; source-dir target-source-dir))
(log-action (format #f &quot;Moved ~a to ~a&quot; source-dir target-source-dir))))
target-source-dir))
</code></pre>
<p>This implementation:</p>
<ul>
<li>Ensures paths are properly formatted</li>
<li>Creates necessary directories</li>
<li>Handles conflicts gracefully</li>
<li>Logs all operations</li>
<li>Returns the new path for further operations</li>
</ul>
<h2>Lessons Learned</h2>
<h3>What Worked Well</h3>
<ol>
<li><strong>Modular Design</strong>: Breaking the code into focused modules made it easier to maintain and test</li>
<li><strong>Functional Approach</strong>: Using pure functions where possible made the code more predictable</li>
<li><strong>Interactive Interface</strong>: Providing clear user prompts and colored output improved usability</li>
<li><strong>Robust Logging</strong>: Detailed logging helped with debugging and understanding program flow</li>
</ol>
<h3>Challenges Faced</h3>
<ol>
<li><strong>Path Handling</strong>: Dealing with different path formats and edge cases required careful attention</li>
<li><strong>Error States</strong>: Managing various error conditions while keeping the code clean</li>
<li><strong>User Interface</strong>: Balancing between automation and user control</li>
<li><strong>Documentation</strong>: Writing clear documentation that helps users understand the tool</li>
</ol>
<h2>Moving Forward</h2>
<p>Building <code>stash</code> 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.</p>
<h2>Resources</h2>
<ol>
<li><a href="https://www.gnu.org/software/guile/manual/">Guile Manual</a></li>
<li><a href="/content/posts/scheme-journey.html">My Previous Scheme Journey Post</a></li>
<li><a href="https://systemcrafters.net/community">System Crafters Community</a></li>
<li><a href="https://codeberg.org/glenneth/stash">Stash on Codeberg</a></li>
</ol>
<p>The code examples in this post are from my actual implementation of <code>stash</code>. Feel free to explore, use, and improve upon them!</p>
</article>
</div>
</div>
</main>
<footer class="bg-base-darker text-palenight-200 py-12 border-t border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center">
<p class="text-palenight-300">&copy; 2024 Glenn Thompson. All rights reserved.</p>
<div class="webring-text mt-6">
<p class="text-palenight-300">I am part of the <a href="https://systemcrafters.net" target="_blank" class="text-accent-blue hover:text-accent-cyan">System Crafters</a> webring:</p>
</div>
<div class="craftering mt-2 flex items-center justify-center gap-4 text-accent-blue">
<a href="https://craftering.systemcrafters.net/@glenneth/previous" class="hover:text-accent-cyan"></a>
<a href="https://craftering.systemcrafters.net/" class="hover:text-accent-cyan">craftering</a>
<a href="https://craftering.systemcrafters.net/@glenneth/next" class="hover:text-accent-cyan"></a>
</div>
<p class="text-palenight-300 mt-2">
<a href="mailto:glenn@glenneth.org" class="text-accent-blue hover:text-accent-cyan transition-colors">glenn@glenneth.org</a> |
<a href="https://glenneth.org" class="text-accent-blue hover:text-accent-cyan transition-colors">glenneth.org</a>
</p>
</div>
</div>
</footer>
</body>
</html>

File diff suppressed because one or more lines are too long

347
deploy/index.html Normal file
View File

@ -0,0 +1,347 @@
<!DOCTYPE html>
<html lang="en" class="bg-base-bg">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description"
content="Glenn Thompson's personal blog about technology, engineering, and travel experiences in the Middle East">
<meta property="og:title" content="Glenn Thompson - Technology, Engineering & Travel">
<meta property="og:description"
content="Exploring the intersection of electrical engineering, technology, and cultural experiences from two decades in the Middle East">
<meta property="og:url" content="https://glenneth.org">
<title>Glenn Thompson - Technology, Engineering & Travel</title>
<link href="./dist/styles.css" rel="stylesheet">
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Merriweather:wght@400;700&family=JetBrains+Mono:wght@400;700&display=swap"
rel="stylesheet">
<script defer src="./src/js/main.js"></script>
</head>
<body class="bg-base-bg text-palenight-50">
<nav class="fixed w-full bg-base-darker/80 backdrop-blur-sm shadow-sm z-50 border-b border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<a href="#" class="flex items-center font-serif text-xl font-bold text-accent-purple">Glenn
Thompson</a>
</div>
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<a href="#about" class="nav-link text-accent-blue hover:text-accent-cyan">About</a>
<a href="#blog" class="nav-link text-accent-blue hover:text-accent-cyan">Blog</a>
<a href="#projects" class="nav-link text-accent-blue hover:text-accent-cyan">Projects</a>
<a href="#contact" class="nav-link text-accent-blue hover:text-accent-cyan">Contact</a>
</div>
</div>
</div>
</nav>
<main>
<!-- Hero Section -->
<section class="pt-24 pb-16 px-4 sm:pt-32 sm:pb-24 bg-base-bg">
<div class="max-w-7xl mx-auto">
<div class="text-center">
<h1 class="text-4xl font-serif font-bold tracking-tight text-accent-yellow sm:text-6xl">
Technology, Engineering & Travel
</h1>
<p class="mt-6 text-lg leading-8 text-palenight-100 max-w-2xl mx-auto">
Exploring the intersection of electrical engineering, technology, and cultural experiences from
two decades in the Middle East.
</p>
</div>
</div>
</section>
<!-- Featured Posts -->
<section id="blog" class="py-16">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 class="text-3xl font-serif font-bold text-accent-yellow mb-8">Blog Posts</h2>
<div class="grid gap-8 md:grid-cols-2">
<!-- Practical Scheme Post -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-2">
<span>Tech</span>
<span></span>
<time datetime="2024-12-03T10:00:00">December 3, 2024</time>
</div>
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">
<a href="/content/posts/2024-12-03-practical-scheme.html"
class="hover:text-accent-cyan transition-colors">
Beyond Theory: Building Practical Tools with Guile Scheme
</a>
</h3>
<p class="text-palenight-100 mb-4">A deep dive into building real-world tools with Guile Scheme,
featuring modular design, error handling, and practical solutions...</p>
<div class="flex gap-2">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">scheme</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">guile</span>
<span
class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">development</span>
</div>
</article>
<!-- Scheme Journey Post -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-2">
<span>Tech</span>
<span></span>
<time datetime="2024-09-24T09:30:00">September 24, 2024</time>
</div>
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">
<a href="/content/posts/scheme-journey.html"
class="hover:text-accent-cyan transition-colors">
A Journey into Scheme: Building a Simple Symlink Manager
</a>
</h3>
<p class="text-palenight-100 mb-4">Learning Guile Scheme and building a practical tool for
managing symlinks...</p>
<div class="flex gap-2">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">scheme</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">guile</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">gnu</span>
</div>
</article>
<!-- GNU Guix Journey Post -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-2">
<span>Tech</span>
<span></span>
<time datetime="2024-07-26T10:30:00">July 26, 2024</time>
</div>
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">
<a href="/content/posts/gnu-guix-journey.html"
class="hover:text-accent-cyan transition-colors">
A Journey Through GNU Guix: From Installation to Returning to Arch Linux
</a>
</h3>
<p class="text-palenight-100 mb-4">An exploration into GNU Guix, its challenges, and the
eventual return to Arch Linux...</p>
<div class="flex gap-2">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">tech</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">gnu</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">linux</span>
</div>
</article>
<!-- Hugo to Haunt Post -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-2">
<span>Tech</span>
<span></span>
<time datetime="2024-05-15T10:30:00">May 15, 2024</time>
</div>
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">
<a href="/content/posts/hugo-to-haunt.html"
class="hover:text-accent-cyan transition-colors">
Transitioning from Hugo to Haunt: Embracing Scheme and GNU Guix
</a>
</h3>
<p class="text-palenight-100 mb-4">A journey into the world of Scheme, GNU Guix, and static site
generation...</p>
<div class="flex gap-2">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">personal</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">tech</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">scheme</span>
</div>
</article>
<!-- Amman to Newcastle Journey -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-2">
<span>Personal</span>
<span></span>
<time datetime="2024-05-01T17:40:58+03:00">May 1, 2024</time>
</div>
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">
<a href="/content/posts/amman-newcastle-journey.html"
class="hover:text-accent-cyan transition-colors">
A Rollercoaster Week: From Amman to Newcastle, and back again
</a>
</h3>
<p class="text-palenight-100 mb-4">A journey filled with conference presentations, international
travel, and unexpected challenges...</p>
<div class="flex gap-2">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">work</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">travel</span>
</div>
</article>
<!-- Glove80 Review -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-2">
<span>Tech</span>
<span></span>
<time datetime="2024-04-08">April 8, 2024</time>
</div>
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">
<a href="/content/posts/glove80-review.html"
class="hover:text-accent-cyan transition-colors">
Aesthetic Meets Ergonomics: My Deep Dive into the Glove80 Keyboard
</a>
</h3>
<p class="text-palenight-100 mb-4">An in-depth review exploring the unique design, features, and
impact on typing comfort of the Glove80 ergonomic keyboard...</p>
<div class="flex gap-2">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">keyboards</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">tech</span>
</div>
</article>
</div>
</div>
</section>
<!-- Projects Section -->
<section id="projects" class="py-16 bg-base-darker">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 class="text-3xl font-serif font-bold text-accent-yellow mb-8">Projects</h2>
<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
<!-- Personal Website Project -->
<article
class="bg-base-bg p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">Personal Website</h3>
<p class="text-palenight-100 mb-4">A modern, responsive personal website built with HTML,
TailwindCSS, and JavaScript. Features a dark theme and blog functionality.</p>
<div class="flex gap-2 mb-4">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-darker text-xs">HTML</span>
<span
class="text-palenight-300 px-2 py-1 rounded-full bg-base-darker text-xs">TailwindCSS</span>
<span
class="text-palenight-300 px-2 py-1 rounded-full bg-base-darker text-xs">JavaScript</span>
</div>
<a href="https://github.com/glenneth1/personal-website"
class="text-accent-cyan hover:text-accent-purple transition-colors">View Source →</a>
</article>
<!-- Symlink Manager Project -->
<article
class="bg-base-bg p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">Scheme Symlink Manager</h3>
<p class="text-palenight-100 mb-4">A command-line tool built with Guile Scheme for managing
symbolic links in Unix-like systems. Simplifies dotfile management.</p>
<div class="flex gap-2 mb-4">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-darker text-xs">Scheme</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-darker text-xs">Guile</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-darker text-xs">CLI</span>
</div>
<a href="#" class="text-accent-cyan hover:text-accent-purple transition-colors">Coming Soon
</a>
</article>
<!-- Add Project Card -->
<article
class="bg-base-bg p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors flex items-center justify-center">
<div class="text-center">
<p class="text-palenight-100 mb-2">More projects coming soon!</p>
<p class="text-accent-cyan">Stay tuned...</p>
</div>
</article>
</div>
</div>
</section>
<!-- About Section -->
<section id="about" class="py-16 bg-base-bg">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
<div>
<h2 class="text-3xl font-serif font-bold text-accent-purple mb-6">About Me</h2>
<p class="text-palenight-100 mb-4">
With over 20 years in the electrical engineering field, I've had the privilege of working on
groundbreaking projects across the Middle East. My journey has been marked by continuous
learning, cultural exploration, and technological innovation.
</p>
<p class="text-palenight-100 mb-4">
Beyond my professional work, I'm passionate about technology, particularly static site
generation, Scheme programming, and tools like GNU Guix and Haunt. This blog is where I
share my experiences, insights, and the lessons learned along the way.
</p>
</div>
<div class="bg-base-darker p-8 rounded-lg shadow-md border border-palenight-400/20">
<h3 class="text-xl font-bold text-accent-yellow mb-4">Areas of Focus</h3>
<ul class="space-y-3">
<li class="flex items-center text-palenight-100">
<svg class="w-5 h-5 text-accent-blue mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd"></path>
</svg>
Electrical Engineering
</li>
<li class="flex items-center text-palenight-100">
<svg class="w-5 h-5 text-accent-blue mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd"></path>
</svg>
Static Site Generation
</li>
<li class="flex items-center text-palenight-100">
<svg class="w-5 h-5 text-accent-blue mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd"></path>
</svg>
Scheme Programming
</li>
<li class="flex items-center text-palenight-100">
<svg class="w-5 h-5 text-accent-blue mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd"></path>
</svg>
Middle Eastern Culture
</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Contact Section -->
<section id="contact" class="py-16 bg-base-darker">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center">
<h2 class="text-3xl font-serif font-bold text-accent-purple mb-6">Get in Touch</h2>
<p class="text-palenight-100 mb-8">
Interested in connecting? Feel free to reach out for discussions about technology, engineering,
or sharing travel stories.
</p>
<a href="mailto:glenn@glenneth.org"
class="inline-flex items-center px-6 py-3 border border-accent-blue text-base font-medium rounded-md text-accent-blue hover:bg-accent-blue hover:text-base-bg transition-colors">
Send a Message
</a>
</div>
</div>
</section>
</main>
<footer class="bg-base-darker text-palenight-200 py-12 border-t border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center">
<p class="text-palenight-300">&copy; 2024 Glenn Thompson. All rights reserved.</p>
<div class="webring-text mt-6">
<p class="text-palenight-300">I am part of the <a href="https://systemcrafters.net" target="_blank"
class="text-accent-blue hover:text-accent-cyan">System Crafters</a> webring:</p>
</div>
<div class="craftering mt-2 flex items-center justify-center gap-4 text-accent-blue">
<a href="https://craftering.systemcrafters.net/@glenneth/previous"
class="hover:text-accent-cyan">←</a>
<a href="https://craftering.systemcrafters.net/" class="hover:text-accent-cyan">craftering</a>
<a href="https://craftering.systemcrafters.net/@glenneth/next" class="hover:text-accent-cyan"></a>
</div>
<p class="text-palenight-300 mt-2">
<a href="mailto:glenn@glenneth.org"
class="text-accent-blue hover:text-accent-cyan transition-colors">glenn@glenneth.org</a> |
<a href="https://glenneth.org"
class="text-accent-blue hover:text-accent-cyan transition-colors">glenneth.org</a>
</p>
</div>
</div>
</footer>
</body>
</html>

View File

@ -40,16 +40,30 @@ function convertMarkdownToHtml(mdFilePath) {
const metadata = {};
const content = markdown.replace(/^---\n([\s\S]*?)\n---\n/, (_, frontMatter) => {
frontMatter.split('\n').forEach(line => {
const [key, value] = line.split(': ');
if (key && value) {
metadata[key.trim()] = value.trim();
const [key, ...valueParts] = line.split(':');
if (key && valueParts.length > 0) {
metadata[key.trim()] = valueParts.join(':').trim();
}
});
return '';
});
// Configure marked options for proper heading rendering
const markedOptions = {
headerIds: true,
gfm: true,
breaks: true,
pedantic: false,
smartLists: true,
smartypants: true
};
// Convert markdown to HTML
const articleContent = marked.parse(content, options);
const articleContent = marked.parse(content, markedOptions);
// Calculate read time (rough estimate: 200 words per minute)
const wordCount = content.trim().split(/\s+/).length;
const readTime = Math.ceil(wordCount / 200);
// Create full HTML document
const html = `<!DOCTYPE html>
@ -57,36 +71,108 @@ function convertMarkdownToHtml(mdFilePath) {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="${metadata.description || ''}">
<meta property="og:title" content="${metadata.title || 'Blog Post'}">
<meta property="og:description" content="${metadata.description || ''}">
<meta property="og:url" content="https://glenneth.org/${mdFilePath.replace(/\.md$/, '.html')}">
<title>${metadata.title || 'Blog Post'} - Glenn Thompson</title>
<link href="/dist/styles.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;700&family=Merriweather:wght@400;700&display=swap" rel="stylesheet">
<link href="../../dist/styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Merriweather:wght@400;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
.prose-palenight {
--tw-prose-body: #bfc7d5;
--tw-prose-headings: #ffd580;
--tw-prose-links: #82aaff;
--tw-prose-code: #c792ea;
--tw-prose-pre-bg: #1b1e2b;
}
.prose h2 {
color: var(--tw-prose-headings);
font-family: Merriweather, serif;
font-weight: 700;
font-size: 1.5rem;
margin-top: 2rem;
margin-bottom: 1rem;
}
.prose p {
margin-bottom: 1rem;
line-height: 1.625;
}
.prose a {
color: var(--tw-prose-links);
text-decoration: none;
}
.prose a:hover {
color: #89ddff;
}
.prose code {
color: var(--tw-prose-code);
font-family: 'JetBrains Mono', monospace;
}
.prose pre {
background-color: var(--tw-prose-pre-bg);
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
margin-bottom: 1rem;
}
.prose ul, .prose ol {
margin-top: 0.5rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.prose ul {
list-style-type: disc;
}
.prose ol {
list-style-type: decimal;
}
</style>
</head>
<body class="bg-base-bg text-palenight-200 font-sans">
<header class="bg-base-darker border-b border-palenight-400/20">
<nav class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div class="flex justify-between items-center">
<a href="/" class="text-2xl font-serif font-bold text-accent-yellow hover:text-accent-cyan transition-colors">Glenn Thompson</a>
<div class="flex space-x-6">
<a href="/" class="text-palenight-200 hover:text-accent-cyan transition-colors">Home</a>
<a href="/#blog" class="text-palenight-200 hover:text-accent-cyan transition-colors">Blog</a>
<body class="bg-base-bg text-palenight-50">
<nav class="fixed w-full bg-base-darker/80 backdrop-blur-sm shadow-sm z-50 border-b border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<a href="/" class="flex items-center font-serif text-xl font-bold text-accent-purple">Glenn Thompson</a>
</div>
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<a href="/#about" class="nav-link text-accent-blue hover:text-accent-cyan">About</a>
<a href="/#blog" class="nav-link text-accent-blue hover:text-accent-cyan">Blog</a>
<a href="/#projects" class="nav-link text-accent-blue hover:text-accent-cyan">Projects</a>
</div>
</div>
</nav>
</header>
</div>
</nav>
<main class="py-12">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<article class="prose prose-invert prose-palenight max-w-none">
<h1>${metadata.title || 'Blog Post'}</h1>
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-8">
<span>${metadata.category || 'Blog'}</span>
<span></span>
<time datetime="${metadata.date || ''}">${metadata.date || ''}</time>
<main class="pt-24 pb-16 px-4">
<div class="max-w-4xl mx-auto">
<div class="content text-palenight-100 space-y-6">
<div class="flex items-center justify-between mb-8">
<a href="/" class="inline-flex items-center text-accent-blue hover:text-accent-cyan transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd" />
</svg>
Back to Home
</a>
<time datetime="${metadata.date || ''}" class="text-palenight-300">${metadata.date || ''}</time>
</div>
${articleContent}
</article>
<header class="mb-8">
<h1 class="text-4xl font-serif font-bold text-accent-yellow">${metadata.title || 'Blog Post'}</h1>
<div class="flex items-center gap-4 text-palenight-300 mt-4">
<time datetime="${metadata.date || ''}">${metadata.date || ''}</time>
<span></span>
<span>${readTime} min read</span>
<span></span>
<span>By ${metadata.author || 'Glenn Thompson'}</span>
</div>
</header>
<article class="prose prose-palenight max-w-none">
${articleContent}
</article>
</div>
</div>
</main>${footer}`;

2
dist/styles.css vendored

File diff suppressed because one or more lines are too long

View File

@ -57,6 +57,29 @@
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 class="text-3xl font-serif font-bold text-accent-yellow mb-8">Blog Posts</h2>
<div class="grid gap-8 md:grid-cols-2">
<!-- Practical Scheme Post -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-2">
<span>Tech</span>
<span></span>
<time datetime="2024-12-03T10:00:00">December 3, 2024</time>
</div>
<h3 class="text-xl font-serif font-bold text-accent-yellow mb-3">
<a href="/content/posts/2024-12-03-practical-scheme.html"
class="hover:text-accent-cyan transition-colors">
Beyond Theory: Building Practical Tools with Guile Scheme
</a>
</h3>
<p class="text-palenight-100 mb-4">A deep dive into building real-world tools with Guile Scheme,
featuring modular design, error handling, and practical solutions...</p>
<div class="flex gap-2">
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">scheme</span>
<span class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">guile</span>
<span
class="text-palenight-300 px-2 py-1 rounded-full bg-base-bg text-xs">development</span>
</div>
</article>
<!-- Scheme Journey Post -->
<article
class="bg-base-darker p-6 rounded-lg shadow-lg border border-palenight-400/20 hover:border-accent-purple/40 transition-colors">

View File

@ -40,16 +40,30 @@ function convertMarkdownToHtml(mdFilePath) {
const metadata = {};
const content = markdown.replace(/^---\n([\s\S]*?)\n---\n/, (_, frontMatter) => {
frontMatter.split('\n').forEach(line => {
const [key, value] = line.split(': ');
if (key && value) {
metadata[key.trim()] = value.trim();
const [key, ...valueParts] = line.split(':');
if (key && valueParts.length > 0) {
metadata[key.trim()] = valueParts.join(':').trim();
}
});
return '';
});
// Configure marked options for proper heading rendering
const markedOptions = {
headerIds: true,
gfm: true,
breaks: true,
pedantic: false,
smartLists: true,
smartypants: true
};
// Convert markdown to HTML
const articleContent = marked.parse(content, options);
const articleContent = marked.parse(content, markedOptions);
// Calculate read time (rough estimate: 200 words per minute)
const wordCount = content.trim().split(/\s+/).length;
const readTime = Math.ceil(wordCount / 200);
// Create full HTML document
const html = `<!DOCTYPE html>
@ -57,36 +71,108 @@ function convertMarkdownToHtml(mdFilePath) {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="${metadata.description || ''}">
<meta property="og:title" content="${metadata.title || 'Blog Post'}">
<meta property="og:description" content="${metadata.description || ''}">
<meta property="og:url" content="https://glenneth.org${mdFilePath.replace(/\.md$/, '')}">
<title>${metadata.title || 'Blog Post'} - Glenn Thompson</title>
<link href="/dist/styles.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;700&family=Merriweather:wght@400;700&display=swap" rel="stylesheet">
<link href="../../dist/styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Merriweather:wght@400;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
.prose-palenight {
--tw-prose-body: #bfc7d5;
--tw-prose-headings: #ffd580;
--tw-prose-links: #82aaff;
--tw-prose-code: #c792ea;
--tw-prose-pre-bg: #1b1e2b;
}
.prose h2 {
color: var(--tw-prose-headings);
font-family: Merriweather, serif;
font-weight: 700;
font-size: 1.5rem;
margin-top: 2rem;
margin-bottom: 1rem;
}
.prose p {
margin-bottom: 1rem;
line-height: 1.625;
}
.prose a {
color: var(--tw-prose-links);
text-decoration: none;
}
.prose a:hover {
color: #89ddff;
}
.prose code {
color: var(--tw-prose-code);
font-family: 'JetBrains Mono', monospace;
}
.prose pre {
background-color: var(--tw-prose-pre-bg);
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
margin-bottom: 1rem;
}
.prose ul, .prose ol {
margin-top: 0.5rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.prose ul {
list-style-type: disc;
}
.prose ol {
list-style-type: decimal;
}
</style>
</head>
<body class="bg-base-bg text-palenight-200 font-sans">
<header class="bg-base-darker border-b border-palenight-400/20">
<nav class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div class="flex justify-between items-center">
<a href="/" class="text-2xl font-serif font-bold text-accent-yellow hover:text-accent-cyan transition-colors">Glenn Thompson</a>
<div class="flex space-x-6">
<a href="/" class="text-palenight-200 hover:text-accent-cyan transition-colors">Home</a>
<a href="/#blog" class="text-palenight-200 hover:text-accent-cyan transition-colors">Blog</a>
<body class="bg-base-bg text-palenight-50">
<nav class="fixed w-full bg-base-darker/80 backdrop-blur-sm shadow-sm z-50 border-b border-palenight-400/20">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<a href="/" class="flex items-center font-serif text-xl font-bold text-accent-purple">Glenn Thompson</a>
</div>
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<a href="/#about" class="nav-link text-accent-blue hover:text-accent-cyan">About</a>
<a href="/#blog" class="nav-link text-accent-blue hover:text-accent-cyan">Blog</a>
<a href="/#projects" class="nav-link text-accent-blue hover:text-accent-cyan">Projects</a>
</div>
</div>
</nav>
</header>
</div>
</nav>
<main class="py-12">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<article class="prose prose-invert prose-palenight max-w-none">
<h1>${metadata.title || 'Blog Post'}</h1>
<div class="flex items-center gap-2 text-accent-cyan text-sm mb-8">
<span>${metadata.category || 'Blog'}</span>
<span></span>
<time datetime="${metadata.date || ''}">${metadata.date || ''}</time>
<main class="pt-24 pb-16 px-4">
<div class="max-w-4xl mx-auto">
<div class="content text-palenight-100 space-y-6">
<div class="flex items-center justify-between mb-8">
<a href="/" class="inline-flex items-center text-accent-blue hover:text-accent-cyan transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd" />
</svg>
Back to Home
</a>
<time datetime="${metadata.date || ''}" class="text-palenight-300">${metadata.date || ''}</time>
</div>
${articleContent}
</article>
<header class="mb-8">
<h1 class="text-4xl font-serif font-bold text-accent-yellow">${metadata.title || 'Blog Post'}</h1>
<div class="flex items-center gap-4 text-palenight-300 mt-4">
<time datetime="${metadata.date || ''}">${metadata.date || ''}</time>
<span></span>
<span>${readTime} min read</span>
<span></span>
<span>By ${metadata.author || 'Glenn Thompson'}</span>
</div>
</header>
<article class="prose prose-palenight max-w-none">
${articleContent}
</article>
</div>
</div>
</main>${footer}`;

Binary file not shown.