From f0ca9b7fb7877d98d5aadc3412ef1aa8fe499502 Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Mon, 10 Mar 2025 11:08:33 -0400
Subject: [PATCH 1/9] feat(babel): add shebang support for tangled code blocks

Add the ability to include a shebang line at the beginning of tangled code files
by supporting the `:shebang` header argument. The shebang value is cleaned of
quotes and inserted as the first line of the tangled content.
---
 lua/orgmode/babel/tangle.lua | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index 0d317b65a..612b70781 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -60,6 +60,13 @@ function Tangle:tangle()
       vim.fn.mkdir(path, 'p')
     end
 
+    local shebang = info.header_args[':shebang']
+    if shebang then
+      shebang = shebang:gsub('[\'"]', '')
+      utils.echo_info(('shebang: %s'):format(shebang))
+      table.insert(parsed_content, 1, shebang)
+    end
+
     if info.name then
       block_content_by_name[info.name] = parsed_content
     end

From ef7e508c58516efdbda0d4df339c103b6006a28e Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Tue, 11 Mar 2025 01:13:40 -0400
Subject: [PATCH 2/9] feat(babel): Support the tangle-mode source block header

This header allow the creator to change the generated file permissions.
---
 lua/orgmode/babel/tangle.lua | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index 612b70781..60e5ff645 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -35,11 +35,12 @@ function Tangle:tangle()
 
   for _, info in ipairs(valid_blocks) do
     if tangle_info[info.filename] then
-      table.insert(tangle_info[info.filename], '')
+      table.insert(tangle_info[info.filename]['content'], '')
     else
-      tangle_info[info.filename] = {}
+      tangle_info[info.filename] = {content = {}}
     end
 
+    local filemode = tangle_info[info.filename]['mode']
     local do_noweb = info.header_args[':noweb'] == 'yes' or info.header_args[':noweb'] == 'tangle'
     local parsed_content = info.content
 
@@ -63,19 +64,33 @@ function Tangle:tangle()
     local shebang = info.header_args[':shebang']
     if shebang then
       shebang = shebang:gsub('[\'"]', '')
-      utils.echo_info(('shebang: %s'):format(shebang))
       table.insert(parsed_content, 1, shebang)
+      if filemode == nil then
+        filemode = "o755"
+      end
+    end
+
+    local tangle_mode = info.header_args[':tangle-mode']
+    if tangle_mode then
+      filemode = tangle_mode:gsub('[\'"]', '')
     end
 
     if info.name then
       block_content_by_name[info.name] = parsed_content
     end
-    vim.list_extend(tangle_info[info.filename], parsed_content)
+    vim.list_extend(tangle_info[info.filename]['content'], parsed_content)
+    tangle_info[info.filename]['mode'] = filemode
   end
 
   local promises = {}
-  for filename, content in pairs(tangle_info) do
-    table.insert(promises, utils.writefile(filename, table.concat(self:_remove_obsolete_indent(content), '\n')))
+  for filename, block in pairs(tangle_info) do
+    table.insert(promises, utils.writefile(filename, table.concat(self:_remove_obsolete_indent(block['content']), '\n')))
+    local mode_str = block['mode']
+    if mode_str and mode_str:sub(1, 1) == 'o' then
+      mode_str = mode_str:sub(2)
+      local mode_num = tonumber(mode_str, 8)
+      vim.loop.fs_chmod(filename, mode_num)
+    end
   end
   Promise.all(promises):wait()
   utils.echo_info(('Tangled %d blocks from %s'):format(#valid_blocks, vim.fn.fnamemodify(self.file.filename, ':t')))

From d27db588adfb28e21896d8535e9b18d2fe97cac0 Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Tue, 11 Mar 2025 01:21:52 -0400
Subject: [PATCH 3/9] feat(babel): add directory creation support with :mkdirp
 header argument

When tangling code blocks to files, automatically create parent directories
when the :mkdirp header argument is set to 'yes'.
---
 lua/orgmode/babel/tangle.lua | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index 60e5ff645..a57b93c65 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -75,6 +75,11 @@ function Tangle:tangle()
       filemode = tangle_mode:gsub('[\'"]', '')
     end
 
+    if info.header_args[':mkdirp'] == 'yes' then
+      local path = vim.fn.fnamemodify(info.filename, ':h')
+      vim.fn.mkdir(path, "p")
+    end
+
     if info.name then
       block_content_by_name[info.name] = parsed_content
     end

From 556578d90f2ab91e22268c613177af1107ebdc54 Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Tue, 11 Mar 2025 00:11:01 -0400
Subject: [PATCH 4/9] fix(babel): replace double quotes with single quotes.

Coding style requires single quotes
---
 lua/orgmode/babel/tangle.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index a57b93c65..f38c0af7e 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -77,7 +77,7 @@ function Tangle:tangle()
 
     if info.header_args[':mkdirp'] == 'yes' then
       local path = vim.fn.fnamemodify(info.filename, ':h')
-      vim.fn.mkdir(path, "p")
+      vim.fn.mkdir(path, 'p')
     end
 
     if info.name then

From a2a3ef8d7b1b939069d343a9fb1880b258a45849 Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Mon, 10 Mar 2025 11:08:33 -0400
Subject: [PATCH 5/9] feat(babel): add shebang support for tangled code blocks

Add the ability to include a shebang line at the beginning of tangled code files
by supporting the `:shebang` header argument. The shebang value is cleaned of
quotes and inserted as the first line of the tangled content.
---
 lua/orgmode/babel/tangle.lua | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index f38c0af7e..566e73e4b 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -80,6 +80,13 @@ function Tangle:tangle()
       vim.fn.mkdir(path, 'p')
     end
 
+    local shebang = info.header_args[':shebang']
+    if shebang then
+      shebang = shebang:gsub('[\'"]', '')
+      utils.echo_info(('shebang: %s'):format(shebang))
+      table.insert(parsed_content, 1, shebang)
+    end
+
     if info.name then
       block_content_by_name[info.name] = parsed_content
     end

From 52b345dbba96799da4adc61641e919b77a048416 Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Tue, 11 Mar 2025 01:30:11 -0400
Subject: [PATCH 6/9] fix(babel): remove debug messages

They keep showing up.
---
 lua/orgmode/babel/tangle.lua | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index 566e73e4b..b6ce9877b 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -83,7 +83,6 @@ function Tangle:tangle()
     local shebang = info.header_args[':shebang']
     if shebang then
       shebang = shebang:gsub('[\'"]', '')
-      utils.echo_info(('shebang: %s'):format(shebang))
       table.insert(parsed_content, 1, shebang)
     end
 

From 0a45dc0a2156b6d73f735c8b334d69504c8c42b2 Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Wed, 19 Mar 2025 13:19:47 -0400
Subject: [PATCH 7/9] fix: lint error, replace double quotes with single quotes

---
 lua/orgmode/babel/tangle.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index b6ce9877b..dbf445108 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -66,7 +66,7 @@ function Tangle:tangle()
       shebang = shebang:gsub('[\'"]', '')
       table.insert(parsed_content, 1, shebang)
       if filemode == nil then
-        filemode = "o755"
+        filemode = 'o755'
       end
     end
 

From f91330ef847082fb3f7aa0f203e47e4d7045e382 Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Wed, 19 Mar 2025 13:51:47 -0400
Subject: [PATCH 8/9] fix: linter errors

---
 lua/orgmode/babel/tangle.lua | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index dbf445108..647dd3c77 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -37,7 +37,7 @@ function Tangle:tangle()
     if tangle_info[info.filename] then
       table.insert(tangle_info[info.filename]['content'], '')
     else
-      tangle_info[info.filename] = {content = {}}
+      tangle_info[info.filename] = { content = {} }
     end
 
     local filemode = tangle_info[info.filename]['mode']
@@ -95,7 +95,11 @@ function Tangle:tangle()
 
   local promises = {}
   for filename, block in pairs(tangle_info) do
-    table.insert(promises, utils.writefile(filename, table.concat(self:_remove_obsolete_indent(block['content']), '\n')))
+    table.insert(
+      promises, 
+      utils.writefile(filename, table.concat(self:_remove_obsolete_indent(block['content']), '\n'))
+    )
+
     local mode_str = block['mode']
     if mode_str and mode_str:sub(1, 1) == 'o' then
       mode_str = mode_str:sub(2)

From 160fe5f11acb2b6182285893e21fc3a2e718d18f Mon Sep 17 00:00:00 2001
From: Steve Beaulac <steve@beaulac.me>
Date: Wed, 19 Mar 2025 13:54:12 -0400
Subject: [PATCH 9/9] fix: remove trailing spaces

---
 lua/orgmode/babel/tangle.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lua/orgmode/babel/tangle.lua b/lua/orgmode/babel/tangle.lua
index 647dd3c77..f6119d073 100644
--- a/lua/orgmode/babel/tangle.lua
+++ b/lua/orgmode/babel/tangle.lua
@@ -96,7 +96,7 @@ function Tangle:tangle()
   local promises = {}
   for filename, block in pairs(tangle_info) do
     table.insert(
-      promises, 
+      promises,
       utils.writefile(filename, table.concat(self:_remove_obsolete_indent(block['content']), '\n'))
     )