Compare commits
12 Commits
6d8a621b07
...
range_inst
| Author | SHA1 | Date | |
|---|---|---|---|
| 3101834051 | |||
| 8ddcf1de22 | |||
| 15e62ed479 | |||
| a8315e32f1 | |||
| 9cb17ede39 | |||
| cd60b775f5 | |||
| da85946d6a | |||
| 24fcd48036 | |||
| ddbc923314 | |||
| dfef1e6dfa | |||
| 6939353f9c | |||
| 28abca7572 |
@@ -1,18 +1,18 @@
|
|||||||
#? Config file for btop v. 1.4.4
|
#? Config file for btop v.1.4.6
|
||||||
|
|
||||||
#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes.
|
#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes.
|
||||||
#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes"
|
#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes"
|
||||||
color_theme = "/usr/share/btop/themes/everforest-dark-medium.theme"
|
color_theme = "/usr/share/btop/themes/everforest-dark-medium.theme"
|
||||||
|
|
||||||
#* If the theme set background should be shown, set to False if you want terminal background transparency.
|
#* If the theme set background should be shown, set to False if you want terminal background transparency.
|
||||||
theme_background = False
|
theme_background = false
|
||||||
|
|
||||||
#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false.
|
#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false.
|
||||||
truecolor = True
|
truecolor = true
|
||||||
|
|
||||||
#* Set to true to force tty mode regardless if a real tty has been detected or not.
|
#* Set to true to force tty mode regardless if a real tty has been detected or not.
|
||||||
#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols.
|
#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols.
|
||||||
force_tty = False
|
force_tty = false
|
||||||
|
|
||||||
#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.
|
#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.
|
||||||
#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box.
|
#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box.
|
||||||
@@ -22,10 +22,13 @@ presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:defaul
|
|||||||
|
|
||||||
#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists.
|
#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists.
|
||||||
#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift.
|
#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift.
|
||||||
vim_keys = True
|
vim_keys = true
|
||||||
|
|
||||||
#* Rounded corners on boxes, is ignored if TTY mode is ON.
|
#* Rounded corners on boxes, is ignored if TTY mode is ON.
|
||||||
rounded_corners = True
|
rounded_corners = true
|
||||||
|
|
||||||
|
#* Use terminal synchronized output sequences to reduce flickering on supported terminals.
|
||||||
|
terminal_sync = true
|
||||||
|
|
||||||
#* Default symbols to use for graph creation, "braille", "block" or "tty".
|
#* Default symbols to use for graph creation, "braille", "block" or "tty".
|
||||||
#* "braille" offers the highest resolution but might not be included in all fonts.
|
#* "braille" offers the highest resolution but might not be included in all fonts.
|
||||||
@@ -60,37 +63,40 @@ update_ms = 2000
|
|||||||
proc_sorting = "cpu lazy"
|
proc_sorting = "cpu lazy"
|
||||||
|
|
||||||
#* Reverse sorting order, True or False.
|
#* Reverse sorting order, True or False.
|
||||||
proc_reversed = False
|
proc_reversed = false
|
||||||
|
|
||||||
#* Show processes as a tree.
|
#* Show processes as a tree.
|
||||||
proc_tree = True
|
proc_tree = true
|
||||||
|
|
||||||
#* Use the cpu graph colors in the process list.
|
#* Use the cpu graph colors in the process list.
|
||||||
proc_colors = True
|
proc_colors = true
|
||||||
|
|
||||||
#* Use a darkening gradient in the process list.
|
#* Use a darkening gradient in the process list.
|
||||||
proc_gradient = True
|
proc_gradient = true
|
||||||
|
|
||||||
#* If process cpu usage should be of the core it's running on or usage of the total available cpu power.
|
#* If process cpu usage should be of the core it's running on or usage of the total available cpu power.
|
||||||
proc_per_core = True
|
proc_per_core = true
|
||||||
|
|
||||||
#* Show process memory as bytes instead of percent.
|
#* Show process memory as bytes instead of percent.
|
||||||
proc_mem_bytes = True
|
proc_mem_bytes = true
|
||||||
|
|
||||||
#* Show cpu graph for each process.
|
#* Show cpu graph for each process.
|
||||||
proc_cpu_graphs = True
|
proc_cpu_graphs = true
|
||||||
|
|
||||||
#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate)
|
#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate)
|
||||||
proc_info_smaps = False
|
proc_info_smaps = false
|
||||||
|
|
||||||
#* Show proc box on left side of screen instead of right.
|
#* Show proc box on left side of screen instead of right.
|
||||||
proc_left = False
|
proc_left = false
|
||||||
|
|
||||||
#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop).
|
#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop).
|
||||||
proc_filter_kernel = False
|
proc_filter_kernel = false
|
||||||
|
|
||||||
#* In tree-view, always accumulate child process resources in the parent process.
|
#* In tree-view, always accumulate child process resources in the parent process.
|
||||||
proc_aggregate = True
|
proc_aggregate = true
|
||||||
|
|
||||||
|
#* Should cpu and memory usage display be preserved for dead processes when paused.
|
||||||
|
keep_dead_proc_usage = false
|
||||||
|
|
||||||
#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available.
|
#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available.
|
||||||
#* Select from a list of detected attributes from the options menu.
|
#* Select from a list of detected attributes from the options menu.
|
||||||
@@ -104,25 +110,28 @@ cpu_graph_lower = "Auto"
|
|||||||
show_gpu_info = "Auto"
|
show_gpu_info = "Auto"
|
||||||
|
|
||||||
#* Toggles if the lower CPU graph should be inverted.
|
#* Toggles if the lower CPU graph should be inverted.
|
||||||
cpu_invert_lower = True
|
cpu_invert_lower = true
|
||||||
|
|
||||||
#* Set to True to completely disable the lower CPU graph.
|
#* Set to True to completely disable the lower CPU graph.
|
||||||
cpu_single_graph = False
|
cpu_single_graph = false
|
||||||
|
|
||||||
#* Show cpu box at bottom of screen instead of top.
|
#* Show cpu box at bottom of screen instead of top.
|
||||||
cpu_bottom = False
|
cpu_bottom = false
|
||||||
|
|
||||||
#* Shows the system uptime in the CPU box.
|
#* Shows the system uptime in the CPU box.
|
||||||
show_uptime = True
|
show_uptime = true
|
||||||
|
|
||||||
|
#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo.
|
||||||
|
show_cpu_watts = true
|
||||||
|
|
||||||
#* Show cpu temperature.
|
#* Show cpu temperature.
|
||||||
check_temp = True
|
check_temp = true
|
||||||
|
|
||||||
#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors.
|
#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors.
|
||||||
cpu_sensor = "Auto"
|
cpu_sensor = "Auto"
|
||||||
|
|
||||||
#* Show temperatures for cpu cores also if check_temp is True and sensors has been found.
|
#* Show temperatures for cpu cores also if check_temp is True and sensors has been found.
|
||||||
show_coretemp = True
|
show_coretemp = true
|
||||||
|
|
||||||
#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core.
|
#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core.
|
||||||
#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine.
|
#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine.
|
||||||
@@ -134,17 +143,20 @@ cpu_core_map = ""
|
|||||||
temp_scale = "celsius"
|
temp_scale = "celsius"
|
||||||
|
|
||||||
#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024.
|
#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024.
|
||||||
base_10_sizes = False
|
base_10_sizes = false
|
||||||
|
|
||||||
#* Show CPU frequency.
|
#* Show CPU frequency.
|
||||||
show_cpu_freq = True
|
show_cpu_freq = true
|
||||||
|
|
||||||
|
#* How to calculate CPU frequency, available values: "first", "range", "lowest", "highest" and "average".
|
||||||
|
freq_mode = "first"
|
||||||
|
|
||||||
#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.
|
#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.
|
||||||
#* Special formatting: /host = hostname | /user = username | /uptime = system uptime
|
#* Special formatting: /host = hostname | /user = username | /uptime = system uptime
|
||||||
clock_format = "%X"
|
clock_format = "%X"
|
||||||
|
|
||||||
#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort.
|
#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort.
|
||||||
background_update = True
|
background_update = true
|
||||||
|
|
||||||
#* Custom cpu model name, empty string to disable.
|
#* Custom cpu model name, empty string to disable.
|
||||||
custom_cpu_name = ""
|
custom_cpu_name = ""
|
||||||
@@ -154,43 +166,43 @@ custom_cpu_name = ""
|
|||||||
disks_filter = ""
|
disks_filter = ""
|
||||||
|
|
||||||
#* Show graphs instead of meters for memory values.
|
#* Show graphs instead of meters for memory values.
|
||||||
mem_graphs = True
|
mem_graphs = true
|
||||||
|
|
||||||
#* Show mem box below net box instead of above.
|
#* Show mem box below net box instead of above.
|
||||||
mem_below_net = True
|
mem_below_net = true
|
||||||
|
|
||||||
#* Count ZFS ARC in cached and available memory.
|
#* Count ZFS ARC in cached and available memory.
|
||||||
zfs_arc_cached = True
|
zfs_arc_cached = true
|
||||||
|
|
||||||
#* If swap memory should be shown in memory box.
|
#* If swap memory should be shown in memory box.
|
||||||
show_swap = True
|
show_swap = true
|
||||||
|
|
||||||
#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk.
|
#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk.
|
||||||
swap_disk = True
|
swap_disk = true
|
||||||
|
|
||||||
#* If mem box should be split to also show disks info.
|
#* If mem box should be split to also show disks info.
|
||||||
show_disks = True
|
show_disks = true
|
||||||
|
|
||||||
#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar.
|
#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar.
|
||||||
only_physical = True
|
only_physical = true
|
||||||
|
|
||||||
#* Read disks list from /etc/fstab. This also disables only_physical.
|
#* Read disks list from /etc/fstab. This also disables only_physical.
|
||||||
use_fstab = True
|
use_fstab = true
|
||||||
|
|
||||||
#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool)
|
#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool)
|
||||||
zfs_hide_datasets = False
|
zfs_hide_datasets = false
|
||||||
|
|
||||||
#* Set to true to show available disk space for privileged users.
|
#* Set to true to show available disk space for privileged users.
|
||||||
disk_free_priv = False
|
disk_free_priv = false
|
||||||
|
|
||||||
#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view.
|
#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view.
|
||||||
show_io_stat = True
|
show_io_stat = true
|
||||||
|
|
||||||
#* Toggles io mode for disks, showing big graphs for disk read/write speeds.
|
#* Toggles io mode for disks, showing big graphs for disk read/write speeds.
|
||||||
io_mode = False
|
io_mode = false
|
||||||
|
|
||||||
#* Set to True to show combined read/write io graphs in io mode.
|
#* Set to True to show combined read/write io graphs in io mode.
|
||||||
io_graph_combined = False
|
io_graph_combined = false
|
||||||
|
|
||||||
#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ".
|
#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ".
|
||||||
#* Example: "/mnt/media:100 /:20 /boot:1".
|
#* Example: "/mnt/media:100 /:20 /boot:1".
|
||||||
@@ -202,10 +214,10 @@ net_download = 100
|
|||||||
net_upload = 100
|
net_upload = 100
|
||||||
|
|
||||||
#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest.
|
#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest.
|
||||||
net_auto = True
|
net_auto = true
|
||||||
|
|
||||||
#* Sync the auto scaling for download and upload to whichever currently has the highest scale.
|
#* Sync the auto scaling for download and upload to whichever currently has the highest scale.
|
||||||
net_sync = True
|
net_sync = true
|
||||||
|
|
||||||
#* Starts with the Network Interface specified here.
|
#* Starts with the Network Interface specified here.
|
||||||
net_iface = ""
|
net_iface = ""
|
||||||
@@ -214,26 +226,32 @@ net_iface = ""
|
|||||||
base_10_bitrate = "Auto"
|
base_10_bitrate = "Auto"
|
||||||
|
|
||||||
#* Show battery stats in top right if battery is present.
|
#* Show battery stats in top right if battery is present.
|
||||||
show_battery = True
|
show_battery = true
|
||||||
|
|
||||||
#* Which battery to use if multiple are present. "Auto" for auto detection.
|
#* Which battery to use if multiple are present. "Auto" for auto detection.
|
||||||
selected_battery = "Auto"
|
selected_battery = "Auto"
|
||||||
|
|
||||||
#* Show power stats of battery next to charge indicator.
|
#* Show power stats of battery next to charge indicator.
|
||||||
show_battery_watts = True
|
show_battery_watts = true
|
||||||
|
|
||||||
#* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
|
#* Set loglevel for "~/.local/state/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
|
||||||
#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info.
|
#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info.
|
||||||
log_level = "WARNING"
|
log_level = "WARNING"
|
||||||
|
|
||||||
|
#* Automatically save current settings to config file on exit.
|
||||||
|
save_config_on_exit = true
|
||||||
|
|
||||||
#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards.
|
#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards.
|
||||||
nvml_measure_pcie_speeds = True
|
nvml_measure_pcie_speeds = true
|
||||||
|
|
||||||
#* Measure PCIe throughput on AMD cards, may impact performance on certain cards.
|
#* Measure PCIe throughput on AMD cards, may impact performance on certain cards.
|
||||||
rsmi_measure_pcie_speeds = True
|
rsmi_measure_pcie_speeds = true
|
||||||
|
|
||||||
#* Horizontally mirror the GPU graph.
|
#* Horizontally mirror the GPU graph.
|
||||||
gpu_mirror_graph = True
|
gpu_mirror_graph = true
|
||||||
|
|
||||||
|
#* Set which GPU vendors to show. Available values are "nvidia amd intel"
|
||||||
|
shown_gpus = "nvidia amd intel"
|
||||||
|
|
||||||
#* Custom gpu0 model name, empty string to disable.
|
#* Custom gpu0 model name, empty string to disable.
|
||||||
custom_gpu_name0 = ""
|
custom_gpu_name0 = ""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -150,7 +150,7 @@
|
|||||||
|
|
||||||
(setq org-global-properties
|
(setq org-global-properties
|
||||||
'(("Effort_ALL" . "0:10 0:30 1:00 2:00 4:00 8:00")
|
'(("Effort_ALL" . "0:10 0:30 1:00 2:00 4:00 8:00")
|
||||||
("ASSIGNEE_ALL" . "Thierry.P Cath.F Martin.K Michel.B Gabriel.C Silvie.L George.G Miguel.A Réjean.S Dominique Adnane Helper1 Helper2")))
|
("ASSIGNEE_ALL" . "Thierry.P Cath.F Martin.K Michel.B Gabriel.C Silvie.L George.G Miguel.A Réjean.S Dominique Adnane Hatim.K Marc-Antoine.P")))
|
||||||
|
|
||||||
(setq org-stuck-projects
|
(setq org-stuck-projects
|
||||||
'("TODO=\"PROJ\"" ("NEXT") nil ""))
|
'("TODO=\"PROJ\"" ("NEXT") nil ""))
|
||||||
@@ -334,14 +334,18 @@
|
|||||||
)
|
)
|
||||||
((org-agenda-tag-filter-preset '("+perso")))
|
((org-agenda-tag-filter-preset '("+perso")))
|
||||||
)
|
)
|
||||||
("wP" "THE PLAN"
|
("wP" "Installation Bombardier"
|
||||||
((agenda ""
|
((agenda ""
|
||||||
((org-agenda-span 'month)
|
((org-agenda-span 90)
|
||||||
(org-agenda-start-day nil)
|
(org-agenda-start-day "2026-01-29")
|
||||||
(org-agenda-overriding-header "📅 THE PLAN"))
|
(org-agenda-overriding-header "📅 Installation Bombardier")
|
||||||
)
|
(org-agenda-prefix-format " %12t") ;; reserve time space
|
||||||
)
|
(org-agenda-todo-keyword-format " %-5s") ;; fixed-width TODO
|
||||||
((org-agenda-tag-filter-preset '("+work")))
|
(org-agenda-tags-column -100) ;; right-align tags
|
||||||
|
(org-agenda-time-grid nil)
|
||||||
|
)))
|
||||||
|
|
||||||
|
((org-agenda-tag-filter-preset '("+BA_ON_SITE")))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -362,6 +366,9 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(after! ox-latex
|
||||||
|
(setq org-latex-compiler "xelatex"))
|
||||||
|
|
||||||
(after! org
|
(after! org
|
||||||
(setq
|
(setq
|
||||||
org-capture-templates
|
org-capture-templates
|
||||||
@@ -390,227 +397,53 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Enable plantuml-mode for PlantUML files
|
(after! org
|
||||||
(add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode))
|
;; Ensure exported HTML opens in the system browser, not inside Emacs
|
||||||
|
(setq org-file-apps
|
||||||
|
(append '(("\\.x?html?\\'" . default))
|
||||||
|
(assq-delete-all "\\.x?html?\\'" org-file-apps))))
|
||||||
|
|
||||||
(require 'cl-lib)
|
(after! grip-mode
|
||||||
(require 'dash)
|
(setq grip-binary-path "/home/tpouplier/.local/bin/grip")
|
||||||
(unless (fboundp 'first) (defalias 'first #'car))
|
|
||||||
|
|
||||||
;; Clear rules to ensure the new global color logic takes effect immediately
|
|
||||||
(setq elgantt--display-rules nil)
|
|
||||||
|
|
||||||
(defface gortium/elgantt-weekend-face
|
|
||||||
'((t (:background "#332222" :extend nil)))
|
|
||||||
"Face for weekend vertical columns in ElGantt.")
|
|
||||||
|
|
||||||
(defun gortium/elgantt-draw-weekend-guides ()
|
|
||||||
"Draw weekend guides for the ENTIRE buffer once to prevent scroll lag."
|
|
||||||
(interactive)
|
|
||||||
(when (derived-mode-p 'elgantt-mode)
|
|
||||||
(let* ((inhibit-modification-hooks t)
|
|
||||||
(header-line-1 (save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(buffer-substring-no-properties (line-beginning-position) (line-end-position))))
|
|
||||||
(col-indices '())
|
|
||||||
(search-pos 0))
|
|
||||||
|
|
||||||
(save-excursion
|
|
||||||
(save-restriction
|
|
||||||
(widen)
|
|
||||||
;; 1. Clear ALL weekend overlays in the entire buffer
|
|
||||||
(remove-overlays (point-min) (point-max) 'gortium-weekend t)
|
|
||||||
|
|
||||||
;; 2. Parse header once to find column indexes (Fast)
|
|
||||||
(while (string-match "|[[:space:]]*\\([[:alpha:]]+\\)[[:space:]]+\\([0-9]\\{4\\}\\)" header-line-1 search-pos)
|
|
||||||
(let* ((month-start-col (match-beginning 0))
|
|
||||||
(month-name (match-string 1 header-line-1))
|
|
||||||
(year (string-to-number (match-string 2 header-line-1)))
|
|
||||||
(month-num (gortium/internal--month-to-num month-name))
|
|
||||||
(next-pipe (string-match "|" header-line-1 (1+ month-start-col)))
|
|
||||||
(month-width (if next-pipe (- next-pipe month-start-col 1) 31)))
|
|
||||||
(dotimes (d month-width)
|
|
||||||
(let* ((day (1+ d))
|
|
||||||
(time (condition-case nil (encode-time 0 0 12 day month-num year) (error nil))))
|
|
||||||
(when time
|
|
||||||
(let ((dow (nth 6 (decode-time time)))
|
|
||||||
(actual-col (+ month-start-col 1 d)))
|
|
||||||
(when (member dow '(0 6))
|
|
||||||
(push actual-col col-indices))))))
|
|
||||||
(setq search-pos (or next-pipe (length header-line-1)))))
|
|
||||||
|
|
||||||
;; 3. Apply to the WHOLE buffer line by line
|
|
||||||
(unless (null col-indices)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line 2) ;; Skip headers
|
|
||||||
(while (not (eobp))
|
|
||||||
(let ((line-end (line-end-position)))
|
|
||||||
(dolist (col col-indices)
|
|
||||||
(move-to-column col)
|
|
||||||
(let ((p (point)))
|
|
||||||
;; Ensure we are still on the same line and at the correct column
|
|
||||||
(when (and (< p line-end) (= (current-column) col))
|
|
||||||
(let ((ov (make-overlay p (1+ p))))
|
|
||||||
(overlay-put ov 'face 'gortium/elgantt-weekend-face)
|
|
||||||
(overlay-put ov 'gortium-weekend t)
|
|
||||||
(overlay-put ov 'priority 100)
|
|
||||||
(overlay-put ov 'evaporate t))))))
|
|
||||||
(forward-line 1)))))
|
|
||||||
(message "Weekend guides rendered for the whole buffer."))))
|
|
||||||
|
|
||||||
;; Run it only once when the buffer is loaded
|
|
||||||
(add-hook 'elgantt-mode-hook #'gortium/elgantt-draw-weekend-guides)
|
|
||||||
|
|
||||||
(use-package! elgantt
|
|
||||||
:commands (elgantt-open elgantt-open-current-org-file)
|
|
||||||
:config
|
|
||||||
;; --- 1. Environment & UI ---
|
|
||||||
(add-hook 'elgantt-mode-hook
|
|
||||||
(lambda ()
|
|
||||||
(setq-local org-phscroll-mode nil)
|
|
||||||
(setq-local image-roll-mode nil)
|
|
||||||
(setq truncate-lines t)))
|
|
||||||
|
|
||||||
(setq elgantt-start-date "2026-01-01")
|
|
||||||
|
|
||||||
(setq elgantt-header-column-offset 40
|
|
||||||
elgantt-header-type 'outline
|
|
||||||
elgantt-show-header-depth t
|
|
||||||
elgantt-insert-blank-line-between-top-level-header t
|
|
||||||
elgantt-startup-folded nil
|
|
||||||
elgantt-draw-overarching-headers nil
|
|
||||||
elgantt-scroll-to-current-month-at-startup t)
|
|
||||||
|
|
||||||
(setq elgantt-user-set-color-priority-counter 0)
|
|
||||||
|
|
||||||
;; --- 2. Effort Rule (With Weekend Extension) ---
|
|
||||||
(elgantt-create-display-rule draw-scheduled-to-effort-end
|
|
||||||
:parser ((override-color . ((when-let ((colors (org-entry-get (point) "ELGANTT-COLOR")))
|
|
||||||
(split-string colors " "))))
|
|
||||||
(elgantt-effort . ((org-entry-get (point) "EFFORT")))
|
|
||||||
(wknd-days . ((when-let ((val (org-entry-get (point) "WEEKEND_DAYS")))
|
|
||||||
(string-to-number val)))))
|
|
||||||
:args (elgantt-scheduled elgantt-effort elgantt-org-id)
|
|
||||||
:body ((when (and elgantt-scheduled elgantt-effort)
|
|
||||||
(let* ((start-ts (ts-parse elgantt-scheduled))
|
|
||||||
(raw-mins (org-duration-to-minutes elgantt-effort))
|
|
||||||
;; Add the weekend jump days to the visual length
|
|
||||||
(total-days (+ (ceiling (/ (float raw-mins) 1440.0)) (or wknd-days 0)))
|
|
||||||
(p1 (save-excursion
|
|
||||||
(elgantt--goto-date (ts-format "%Y-%m-%d" start-ts))
|
|
||||||
(point)))
|
|
||||||
(colors (or override-color '("#8ec07c" "#458588"))))
|
|
||||||
(when (numberp p1)
|
|
||||||
(if (<= total-days 1)
|
|
||||||
(elgantt--create-overlay (truncate p1) (1+ (truncate p1))
|
|
||||||
`(face (:background ,(car colors))
|
|
||||||
priority ,(setq elgantt-user-set-color-priority-counter
|
|
||||||
(1- elgantt-user-set-color-priority-counter))
|
|
||||||
:elgantt-user-overlay ,elgantt-org-id))
|
|
||||||
;; FIX 1: compute p2 by date (handles "|" separators)
|
|
||||||
;; FIX 2: keep original "Rule of 2" behavior to avoid +1 day overshoot
|
|
||||||
(let* ((end-ts (ts-adjust 'day (- total-days 2) start-ts))
|
|
||||||
(p2 (save-excursion
|
|
||||||
(elgantt--goto-date (ts-format "%Y-%m-%d" end-ts))
|
|
||||||
(point))))
|
|
||||||
(when (numberp p2)
|
|
||||||
(elgantt--draw-gradient
|
|
||||||
(car colors) (cadr colors)
|
|
||||||
(truncate p1) (1+ (truncate p2)) nil
|
|
||||||
`(priority ,(setq elgantt-user-set-color-priority-counter
|
|
||||||
(1- elgantt-user-set-color-priority-counter))
|
|
||||||
:elgantt-user-overlay ,elgantt-org-id))))))))))
|
|
||||||
|
|
||||||
;; --- 3. Progress Bar ---
|
|
||||||
(elgantt-create-display-rule pages-read-progress
|
|
||||||
:parser ((total-pages . ((--when-let (org-entry-get (point) "TOTAL_PAGES") (string-to-number it))))
|
|
||||||
(pages-read . ((--when-let (org-entry-get (point) "PAGES_READ") (string-to-number it)))))
|
|
||||||
:args (elgantt-deadline elgantt-scheduled)
|
|
||||||
:body ((when (and elgantt-deadline elgantt-scheduled total-pages pages-read)
|
|
||||||
(let* ((start (save-excursion (elgantt--goto-date elgantt-scheduled) (point)))
|
|
||||||
(end (save-excursion (elgantt--goto-date elgantt-deadline) (point)))
|
|
||||||
(percent (/ (float pages-read) (float total-pages))))
|
|
||||||
(when (and (numberp start) (numberp end))
|
|
||||||
(elgantt--draw-progress-bar "#98be65" "#ff6c6b"
|
|
||||||
(truncate start) (truncate end) percent))))))
|
|
||||||
|
|
||||||
;; --- 4. Blocker Interaction (Smart Append) ---
|
|
||||||
(require 'elgantt-interaction)
|
|
||||||
(elgantt--selection-rule :name mark-blocker
|
|
||||||
:selection-number 2
|
|
||||||
:selection-messages ((1 . "Select the BLOCKING task (Cause)")
|
|
||||||
(2 . "Select the BLOCKED task (Effect)"))
|
|
||||||
:execution-functions
|
|
||||||
((1 . ((elgantt-with-point-at-orig-entry nil (org-id-get-create))))
|
|
||||||
(2 . ((let* ((new-id return-val)
|
|
||||||
(current (elgantt-with-point-at-orig-entry nil (org-entry-get (point) "BLOCKER"))))
|
|
||||||
(elgantt-with-point-at-orig-entry nil
|
|
||||||
(if (and current (string-match "ids(\\(.*?\\))" current))
|
|
||||||
(let ((existing (match-string 1 current)))
|
|
||||||
(org-set-property "BLOCKER" (format "ids(%s %s)" existing new-id)))
|
|
||||||
(org-set-property "BLOCKER" (format "ids(%s)" new-id)))
|
|
||||||
(message "Added blocker: %s" new-id)))))))
|
|
||||||
|
|
||||||
;; --- 5. Blocker Lines (Multi-ID & Sync Support) ---
|
|
||||||
(elgantt-create-display-rule draw-blocker-lines
|
|
||||||
:parser ((blocker-raw . ((org-entry-get (point) "BLOCKER"))))
|
|
||||||
:args (elgantt-org-id)
|
|
||||||
:body ((when (and blocker-raw (not (string-empty-p blocker-raw)))
|
|
||||||
(let* ((p-blocked (point))
|
|
||||||
(ids-string (if (string-match "ids(\\(.*?\\))" blocker-raw)
|
|
||||||
(match-string 1 blocker-raw)
|
|
||||||
blocker-raw))
|
|
||||||
;; Supports spaces or commas as separators
|
|
||||||
(id-list (split-string ids-string "[ ,]+" t)))
|
|
||||||
(dolist (blocker-id id-list)
|
|
||||||
(save-excursion
|
|
||||||
(when (elgantt--goto-id blocker-id)
|
|
||||||
(let* ((blocker-data (elgantt-with-point-at-orig-entry nil
|
|
||||||
(list (org-entry-get (point) "SCHEDULED")
|
|
||||||
(org-entry-get (point) "EFFORT"))))
|
|
||||||
(b-sched (car blocker-data))
|
|
||||||
(b-effort (cadr blocker-data)))
|
|
||||||
(when (and b-sched b-effort)
|
|
||||||
(let* ((start-ts (ts-parse b-sched))
|
|
||||||
(raw-mins (org-duration-to-minutes b-effort))
|
|
||||||
(days-count (ceiling (/ (float raw-mins) 1440.0)))
|
|
||||||
(p-start-base (save-excursion
|
|
||||||
(elgantt--goto-date (ts-format "%Y-%m-%d" start-ts))
|
|
||||||
(point))))
|
|
||||||
(when (and (numberp p-start-base) (numberp p-blocked))
|
|
||||||
;; FIX 1: compute p-line-start by date (handles "|" separators)
|
|
||||||
;; FIX 2: keep original "Rule of 2" behavior to avoid +1 day overshoot
|
|
||||||
(let* ((end-ts (ts-adjust 'day (- days-count 2) start-ts))
|
|
||||||
(p-line-start (save-excursion
|
|
||||||
(elgantt--goto-date (ts-format "%Y-%m-%d" end-ts))
|
|
||||||
(point))))
|
|
||||||
(when (numberp p-line-start)
|
|
||||||
(elgantt--draw-line (truncate p-line-start)
|
|
||||||
(truncate p-blocked)
|
|
||||||
"#b8bb26"))))))))))))))
|
|
||||||
|
|
||||||
;; --- 6. Hashtag Navigation ---
|
|
||||||
(elgantt-create-action follow-hashtag-link-forward
|
|
||||||
:args (elgantt-alltags) :binding "C-M-f"
|
|
||||||
:body ((when-let* ((hashtag (--first (s-starts-with-p "#" it) elgantt-alltags))
|
|
||||||
(match (elgantt--next-match :elgantt-alltags hashtag)))
|
|
||||||
(goto-char (car match)))))
|
|
||||||
|
|
||||||
(elgantt-create-action follow-hashtag-link-backward
|
|
||||||
:args (elgantt-alltags) :binding "C-M-b"
|
|
||||||
:body ((when-let* ((hashtag (--first (s-starts-with-p "#" it) elgantt-alltags))
|
|
||||||
(match (elgantt--previous-match :elgantt-alltags hashtag)))
|
|
||||||
(goto-char (car match)))))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
(defun elgantt-open-current-org-file ()
|
(after! markdown-mode
|
||||||
(interactive)
|
(setq markdown-header-scaling t)
|
||||||
(if-let ((file (buffer-file-name)))
|
(custom-set-faces
|
||||||
(progn
|
'(markdown-header-face-1 ((t
|
||||||
(setq elgantt-agenda-files (list file))
|
:inherit markdown-header-face
|
||||||
(elgantt--reset-org-ql-cache)
|
:foreground "#fabd2f"
|
||||||
(elgantt-open))
|
:height 1.8
|
||||||
(message "No file!")))
|
:weight extra-bold)))
|
||||||
|
'(markdown-header-face-2 ((t
|
||||||
|
:inherit markdown-header-face
|
||||||
|
:foreground "#fe8019"
|
||||||
|
:height 1.4
|
||||||
|
:weight extra-bold)))
|
||||||
|
'(markdown-header-face-3 ((t
|
||||||
|
:inherit markdown-header-face
|
||||||
|
:foreground "#fb4934"
|
||||||
|
:height 1.2
|
||||||
|
:weight bold)))
|
||||||
|
'(markdown-header-face-4 ((t
|
||||||
|
:inherit markdown-header-face
|
||||||
|
:foreground "#b8bb26"
|
||||||
|
:height 1.1
|
||||||
|
:weight bold)))
|
||||||
|
'(markdown-header-face-5 ((t
|
||||||
|
:inherit markdown-header-face
|
||||||
|
:foreground "#83a598"
|
||||||
|
:height 1.0
|
||||||
|
:weight bold)))
|
||||||
|
'(markdown-header-face-6 ((t
|
||||||
|
:inherit markdown-header-face
|
||||||
|
:foreground "#d3869b"
|
||||||
|
:height 1.0
|
||||||
|
:weight bold))))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Enable plantuml-mode for PlantUML files
|
||||||
|
(add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode))
|
||||||
|
|
||||||
(setq org-roam-directory (file-truename "~/ExoKortex/")
|
(setq org-roam-directory (file-truename "~/ExoKortex/")
|
||||||
org-roam-db-location (file-truename "~/ExoKortex/2-Areas/IT/Roam/org-roam.db")
|
org-roam-db-location (file-truename "~/ExoKortex/2-Areas/IT/Roam/org-roam.db")
|
||||||
@@ -1200,7 +1033,9 @@ DIFF:
|
|||||||
)
|
)
|
||||||
|
|
||||||
;; Dirvish config
|
;; Dirvish config
|
||||||
(after! dirvish
|
(after! (dirvish dired)
|
||||||
|
(require 'async)
|
||||||
|
(dired-async-mode 1)
|
||||||
;; Display icons, file size, timestamps, etc.
|
;; Display icons, file size, timestamps, etc.
|
||||||
(setq dirvish-attributes
|
(setq dirvish-attributes
|
||||||
'(nerd-icons
|
'(nerd-icons
|
||||||
@@ -1233,7 +1068,10 @@ DIFF:
|
|||||||
("d" "~/Downloads/" "Downloads")
|
("d" "~/Downloads/" "Downloads")
|
||||||
("u" "/run/media" "Mounted drives")
|
("u" "/run/media" "Mounted drives")
|
||||||
("t" "~/.local/share/Trash/files/" "Trash")
|
("t" "~/.local/share/Trash/files/" "Trash")
|
||||||
)))
|
))
|
||||||
|
(setq dirvish-yank-use-rsync t)
|
||||||
|
(setq dirvish-yank-rsync-args '("-ah" "--info=progress2"))
|
||||||
|
)
|
||||||
|
|
||||||
;; Use `p` to open the yank menu
|
;; Use `p` to open the yank menu
|
||||||
(map! :after dirvish-yank
|
(map! :after dirvish-yank
|
||||||
@@ -1540,216 +1378,439 @@ If FILE is nil, refile in the current file."
|
|||||||
|
|
||||||
(add-hook 'ediff-prepare-buffer-hook 'org-ediff-prepare-buffer)
|
(add-hook 'ediff-prepare-buffer-hook 'org-ediff-prepare-buffer)
|
||||||
|
|
||||||
(defun gortium/add-trigger-scheduling-next ()
|
;;; ============================================================
|
||||||
"Add scheduled chain for this entry."
|
;;; GORTIUM — Org chain scheduler (Safe & Optimized with Debugging)
|
||||||
(interactive)
|
;;; ============================================================
|
||||||
(org-set-property "TRIGGER" "next-sibling scheduled!(\"++0d\") todo!(NEXT) chain!(\"TRIGGER\")"))
|
|
||||||
|
|
||||||
(defun gortium/org-schedule-after-previous-sibling ()
|
(require 'org)
|
||||||
"Schedule the current task right after its previous sibling.
|
(require 'org-id)
|
||||||
If the sibling is DONE, use its CLOSED time.
|
(require 'cl-lib)
|
||||||
Otherwise, use SCHEDULED + EFFORT."
|
(require 's)
|
||||||
(interactive)
|
|
||||||
(unless (org-at-heading-p)
|
|
||||||
(org-back-to-heading t))
|
|
||||||
(let ((current-level (org-current-level))
|
|
||||||
(current-point (point))
|
|
||||||
prev-end-time)
|
|
||||||
(save-excursion
|
|
||||||
;; Find previous sibling of same level
|
|
||||||
(let ((found nil))
|
|
||||||
(while (and (not found) (outline-previous-heading))
|
|
||||||
(when (= (org-current-level) current-level)
|
|
||||||
(setq found t)))
|
|
||||||
(unless found
|
|
||||||
(user-error "No previous sibling found"))
|
|
||||||
;; At previous sibling now
|
|
||||||
(let* ((state (org-get-todo-state))
|
|
||||||
(scheduled (org-entry-get nil "SCHEDULED"))
|
|
||||||
(closed (org-entry-get nil "CLOSED"))
|
|
||||||
(effort (org-entry-get nil "EFFORT")))
|
|
||||||
(cond
|
|
||||||
;; If task is DONE and CLOSED exists
|
|
||||||
((and (member state org-done-keywords) closed)
|
|
||||||
(setq prev-end-time (org-time-string-to-time closed)))
|
|
||||||
;; Else use SCHEDULED + EFFORT
|
|
||||||
((and scheduled effort)
|
|
||||||
(let* ((sched-time (org-time-string-to-time scheduled))
|
|
||||||
(duration-min (org-duration-to-minutes effort)))
|
|
||||||
(setq prev-end-time
|
|
||||||
(time-add sched-time (seconds-to-time (* 60 duration-min))))))
|
|
||||||
(t
|
|
||||||
(user-error "Previous sibling missing SCHEDULED/CLOSED or EFFORT"))))))
|
|
||||||
;; Schedule current task
|
|
||||||
(goto-char current-point)
|
|
||||||
(org-schedule nil (format-time-string (org-time-stamp-format t) prev-end-time))))
|
|
||||||
|
|
||||||
;; --- Helper: Snap to working hours (8-16) ---
|
|
||||||
;; --- Helper: Snap to working hours (8-16) ---
|
|
||||||
(defun gortium/internal--snap-to-working-hours (time)
|
|
||||||
(let* ((day-start 8) (day-end 16)
|
|
||||||
(t1 (gortium/org--skip-weekend time))
|
|
||||||
(d (decode-time t1)) (h (nth 2 d)))
|
|
||||||
(cond
|
|
||||||
((< h day-start) (apply #'encode-time (append (list 0 0 day-start) (nthcdr 3 d))))
|
|
||||||
((>= h day-end)
|
|
||||||
(let ((next (time-add t1 (days-to-time 1))))
|
|
||||||
(gortium/org--skip-weekend (apply #'encode-time (append (list 0 0 day-start) (nthcdr 3 (decode-time next)))))))
|
|
||||||
(t t1))))
|
|
||||||
|
|
||||||
;; --- Helper: Calculate End Time & Weekend Jump (THE WALKER FIX) ---
|
|
||||||
(defun gortium/internal--calculate-task-span (start-time effort-str)
|
|
||||||
(if (or (null effort-str) (string-empty-p effort-str))
|
|
||||||
(list start-time 0)
|
|
||||||
(let* ((eff-mins (org-duration-to-minutes effort-str))
|
|
||||||
;; SMART MATH: If string has "d", divide by 1440 (24h). If only "h", divide by 480 (8h).
|
|
||||||
(divisor (if (string-match-p "d" effort-str) 1440.0 480.0))
|
|
||||||
(eff-days (max 1 (ceiling (/ (float eff-mins) divisor))))
|
|
||||||
(cursor start-time)
|
|
||||||
(days-worked 0)
|
|
||||||
(wknd-count 0))
|
|
||||||
|
|
||||||
;; THE WALKER: Simulate the task day by day
|
|
||||||
(while (< days-worked eff-days)
|
|
||||||
(let* ((dow (nth 6 (decode-time cursor))))
|
|
||||||
(cond
|
|
||||||
;; If Sat (6) or Sun (0), it's a weekend. Count it, but don't advance work.
|
|
||||||
((or (= dow 6) (= dow 0))
|
|
||||||
(setq wknd-count (1+ wknd-count))
|
|
||||||
(setq cursor (time-add cursor (days-to-time 1))))
|
|
||||||
;; If Mon-Fri, it's a work day. Advance work count.
|
|
||||||
(t
|
|
||||||
(setq days-worked (1+ days-worked))
|
|
||||||
;; Move cursor to start of next day
|
|
||||||
(setq cursor (time-add cursor (days-to-time 1)))))))
|
|
||||||
|
|
||||||
;; Return [End-Time, Weekend-Days-Count]
|
|
||||||
(list cursor wknd-count))))
|
|
||||||
|
|
||||||
;; --- Helper: Find Blocker End Time ---
|
|
||||||
(defun gortium/internal--get-blocker-end (blocker-str current-pos task-end-map)
|
|
||||||
(let ((clean (s-trim blocker-str)) (latest-time nil))
|
|
||||||
(cond
|
|
||||||
((string-match-p "previous-sibling" clean)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char current-pos)
|
|
||||||
(let ((found nil))
|
|
||||||
(while (and (not found) (org-get-last-sibling))
|
|
||||||
(let* ((sid (org-id-get)) (end (when sid (gethash sid task-end-map))))
|
|
||||||
(when end (setq latest-time end) (setq found t)))))))
|
|
||||||
((string-match-p "parent" clean)
|
|
||||||
(save-excursion (goto-char current-pos)
|
|
||||||
(when (org-up-heading-safe)
|
|
||||||
(setq latest-time (gethash (org-id-get) task-end-map)))))
|
|
||||||
((string-match "ids(\\(.*?\\))" clean)
|
|
||||||
(dolist (tid (split-string (match-string 1 clean) "[ ,]+" t))
|
|
||||||
(let ((tend (gethash (replace-regexp-in-string "[\"']\\|id:" "" tid) task-end-map)))
|
|
||||||
(when (and tend (or (null latest-time) (time-less-p latest-time tend)))
|
|
||||||
(setq latest-time tend))))))
|
|
||||||
latest-time))
|
|
||||||
|
|
||||||
;; --- Helper: Write Properties (Safe) ---
|
|
||||||
(defun gortium/internal--update-properties (pos start wknd id end task-end-map)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char pos) ;; POS is a MARKER
|
|
||||||
(if (and wknd (> wknd 0))
|
|
||||||
(org-entry-put (point) "WEEKEND_DAYS" (number-to-string wknd))
|
|
||||||
(org-entry-put (point) "WEEKEND_DAYS" nil))
|
|
||||||
(org-schedule nil (format-time-string "<%Y-%m-%d %a %H:%M>" start))
|
|
||||||
(puthash id end task-end-map)))
|
|
||||||
|
|
||||||
|
;; ------------------------------------------------------------
|
||||||
|
;; Helper: Skip weekends (snap to next weekday at 08:00)
|
||||||
|
;; ------------------------------------------------------------
|
||||||
(defun gortium/org--skip-weekend (time)
|
(defun gortium/org--skip-weekend (time)
|
||||||
"Advance TIME to the next Monday morning if it falls on a weekend."
|
|
||||||
(let* ((decoded (decode-time time))
|
(let* ((decoded (decode-time time))
|
||||||
(dow (nth 6 decoded)))
|
(dow (nth 6 decoded)))
|
||||||
(cond
|
(cond
|
||||||
((= dow 6) ;; Saturday
|
((= dow 6) ;; Saturday
|
||||||
(let ((next (time-add time (days-to-time 2))))
|
(apply #'encode-time
|
||||||
(apply #'encode-time (append '(0 0 8) (nthcdr 3 (decode-time next))))))
|
(append '(0 0 8)
|
||||||
|
(nthcdr 3 (decode-time (time-add time (days-to-time 2)))))))
|
||||||
((= dow 0) ;; Sunday
|
((= dow 0) ;; Sunday
|
||||||
(let ((next (time-add time (days-to-time 1))))
|
(apply #'encode-time
|
||||||
(apply #'encode-time (append '(0 0 8) (nthcdr 3 (decode-time next))))))
|
(append '(0 0 8)
|
||||||
|
(nthcdr 3 (decode-time (time-add time (days-to-time 1)))))))
|
||||||
(t time))))
|
(t time))))
|
||||||
|
|
||||||
;; --- MAIN FUNCTION ---
|
;; ------------------------------------------------------------
|
||||||
(defun gortium/org-schedule-subtree-chains ()
|
;; Helper: Snap to working hours (08:00–16:00)
|
||||||
"Schedule tasks using MARKERS and WALKER logic."
|
;; ------------------------------------------------------------
|
||||||
(interactive)
|
(defun gortium/internal--snap-to-working-hours (time)
|
||||||
|
(let* ((day-start 8)
|
||||||
|
(day-end 16)
|
||||||
|
(t1 (gortium/org--skip-weekend time))
|
||||||
|
(d (decode-time t1))
|
||||||
|
(h (nth 2 d)))
|
||||||
|
(cond
|
||||||
|
((< h day-start)
|
||||||
|
(apply #'encode-time (append (list 0 0 day-start) (nthcdr 3 d))))
|
||||||
|
((>= h day-end)
|
||||||
|
(let ((next (time-add t1 (days-to-time 1))))
|
||||||
|
(gortium/org--skip-weekend
|
||||||
|
(apply #'encode-time (append (list 0 0 day-start)
|
||||||
|
(nthcdr 3 (decode-time next)))))))
|
||||||
|
(t t1))))
|
||||||
|
|
||||||
|
(defun gortium/org--get-range-end (pos)
|
||||||
|
"Extract the END timestamp from an existing range like <A>--<B> at POS.
|
||||||
|
POS can be a marker or a cons cell (file . position)."
|
||||||
|
(let ((marker (if (markerp pos) pos
|
||||||
|
(let ((file (car pos))
|
||||||
|
(p (cdr pos)))
|
||||||
|
(with-current-buffer (find-file-noselect file)
|
||||||
|
(copy-marker p))))))
|
||||||
|
(with-current-buffer (marker-buffer marker)
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(message "--- Starting Gantt Scheduler ---")
|
(goto-char marker)
|
||||||
(let* ((all-tasks '()) (task-end-times (make-hash-table :test 'equal)))
|
(org-back-to-heading t)
|
||||||
|
(let ((subtree-end (save-excursion (org-end-of-subtree t) (point)))
|
||||||
|
(end-time nil))
|
||||||
|
(save-restriction
|
||||||
|
(narrow-to-region (point) subtree-end)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(when (re-search-forward "<[^>]+>--<\\([^>]+\\)>" nil t)
|
||||||
|
(condition-case nil
|
||||||
|
(setq end-time (org-time-string-to-time (match-string 1)))
|
||||||
|
(error nil))))
|
||||||
|
end-time)))))
|
||||||
|
|
||||||
;; Collection
|
(defun gortium/org--get-range-start (pos)
|
||||||
(org-map-entries
|
"Extract the start timestamp from an existing range like <A>--<B>.
|
||||||
(lambda ()
|
Returns nil if no range found (safe, non-blocking)."
|
||||||
(when (org-get-todo-state) ;; Strict TODO check
|
|
||||||
(let ((effort (org-entry-get (point) "EFFORT" nil))
|
|
||||||
(blocker (org-entry-get (point) "BLOCKER" nil))
|
|
||||||
(fixed (org-entry-get (point) "FIXED" nil))
|
|
||||||
(scheduled (org-entry-get (point) "SCHEDULED")))
|
|
||||||
(when (or effort blocker fixed)
|
|
||||||
(push (list (point-marker) (org-id-get-create) (org-get-heading t t t t)
|
|
||||||
effort (when blocker (s-trim blocker)) fixed scheduled
|
|
||||||
(org-entry-get (point) "OFFSET_DAYS" nil)) all-tasks)))))
|
|
||||||
nil (if (org-at-heading-p) 'tree nil))
|
|
||||||
(setq all-tasks (nreverse all-tasks))
|
|
||||||
|
|
||||||
;; Pass 1: FIXED
|
|
||||||
(dolist (task all-tasks)
|
|
||||||
(pcase-let ((`(,pos ,id ,heading ,effort ,blocker ,fixed ,scheduled ,offset) task))
|
|
||||||
(when (and fixed (member (downcase fixed) '("t" "true" "yes")))
|
|
||||||
(if scheduled
|
|
||||||
(let* ((start (org-time-string-to-time scheduled))
|
|
||||||
(span (gortium/internal--calculate-task-span start effort)))
|
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char pos)
|
(goto-char pos)
|
||||||
(if (and (cadr span) (> (cadr span) 0))
|
(org-back-to-heading t)
|
||||||
(org-entry-put (point) "WEEKEND_DAYS" (number-to-string (cadr span)))
|
(let ((end (save-excursion
|
||||||
(org-entry-put (point) "WEEKEND_DAYS" nil))
|
(or (ignore-errors (outline-next-heading))
|
||||||
(puthash id (car span) task-end-times)))
|
(point-max))
|
||||||
(message "WARNING: Fixed task '%s' missing date." heading)))))
|
(point)))
|
||||||
|
(start-time nil))
|
||||||
|
(save-restriction
|
||||||
|
(narrow-to-region (point) end)
|
||||||
|
(goto-char (point-min))
|
||||||
|
;; Look for range in first 50 lines only (safety limit)
|
||||||
|
(let ((search-limit (save-excursion
|
||||||
|
(forward-line 50)
|
||||||
|
(point))))
|
||||||
|
(when (re-search-forward "<\\([^>]+\\)>--<[^>]+>" search-limit t)
|
||||||
|
(condition-case nil
|
||||||
|
(setq start-time (org-time-string-to-time (match-string 1)))
|
||||||
|
(error nil)))))
|
||||||
|
start-time)))
|
||||||
|
|
||||||
|
(defun gortium/internal--calculate-task-span (start-time effort-str)
|
||||||
|
"Return a list (END-TIME WEEKEND-DAYS) for given START-TIME and EFFORT string."
|
||||||
|
(if (or (null effort-str) (string-empty-p effort-str))
|
||||||
|
(list start-time 0)
|
||||||
|
(let* ((eff-mins (org-duration-to-minutes effort-str))
|
||||||
|
(total-work-mins (if (string-match-p "d" effort-str)
|
||||||
|
(* (/ eff-mins 1440.0) 480)
|
||||||
|
eff-mins))
|
||||||
|
(cursor start-time)
|
||||||
|
(wknd-count 0)
|
||||||
|
(day-start 8)
|
||||||
|
(day-end 16)
|
||||||
|
(safety-counter 0)
|
||||||
|
(max-iterations 1000)) ;; Safety limit
|
||||||
|
(while (and (> total-work-mins 0) (< safety-counter max-iterations))
|
||||||
|
(setq safety-counter (1+ safety-counter))
|
||||||
|
(let* ((decoded (decode-time cursor))
|
||||||
|
(h (nth 2 decoded))
|
||||||
|
(m (nth 1 decoded))
|
||||||
|
(dow (nth 6 decoded))
|
||||||
|
(current-abs-min (+ (* h 60) m))
|
||||||
|
(day-end-abs-min (* day-end 60))
|
||||||
|
(mins-left-today (- day-end-abs-min current-abs-min)))
|
||||||
|
(cond
|
||||||
|
((or (= dow 6) (= dow 0)) ;; weekend
|
||||||
|
(setq wknd-count (1+ wknd-count))
|
||||||
|
(setq cursor (apply #'encode-time (append (list 0 0 day-start)
|
||||||
|
(nthcdr 3 (decode-time
|
||||||
|
(time-add cursor (days-to-time 1))))))))
|
||||||
|
((<= mins-left-today 0) ;; after hours
|
||||||
|
(setq cursor (apply #'encode-time (append (list 0 0 day-start)
|
||||||
|
(nthcdr 3 (decode-time
|
||||||
|
(time-add cursor (days-to-time 1))))))))
|
||||||
|
((<= total-work-mins mins-left-today)
|
||||||
|
(setq cursor (time-add cursor (seconds-to-time (* total-work-mins 60))))
|
||||||
|
(setq total-work-mins 0))
|
||||||
|
(t ;; spill to next day
|
||||||
|
(setq total-work-mins (- total-work-mins mins-left-today))
|
||||||
|
(setq cursor (time-add cursor (seconds-to-time (* mins-left-today 60))))))))
|
||||||
|
|
||||||
|
(when (>= safety-counter max-iterations)
|
||||||
|
(message "WARNING: calculate-task-span hit iteration limit for effort %s" effort-str))
|
||||||
|
|
||||||
|
(list cursor wknd-count))))
|
||||||
|
|
||||||
|
;; ------------------------------------------------------------
|
||||||
|
;; Helper: Find dependency end time
|
||||||
|
;; ------------------------------------------------------------
|
||||||
|
(defun gortium/internal--get-blocker-end (blocker-str task-end-map)
|
||||||
|
"Return the latest end time of all blockers if they are all resolved."
|
||||||
|
(let ((clean (s-trim (format "%s" blocker-str)))
|
||||||
|
(latest-time nil)
|
||||||
|
(all-resolved t))
|
||||||
|
(when (and (string-match "ids(\\(.*?\\))" clean)
|
||||||
|
(not (string-empty-p (s-trim (match-string 1 clean)))))
|
||||||
|
(dolist (tid (split-string (match-string 1 clean) "[[:space:],]+" t))
|
||||||
|
(let* ((clean-id (replace-regexp-in-string "[\"']\\|id: " "" tid))
|
||||||
|
(pos (org-id-find clean-id t))
|
||||||
|
(computed-end (gethash clean-id task-end-map))
|
||||||
|
(blocker-end nil))
|
||||||
|
|
||||||
|
;; 1. Determine this specific blocker's end time
|
||||||
|
(setq blocker-end
|
||||||
|
(cond
|
||||||
|
(computed-end computed-end) ;; Use what we just calculated in this session
|
||||||
|
(pos (let ((m (if (markerp pos) pos
|
||||||
|
(set-marker (make-marker) (cdr pos)
|
||||||
|
(find-file-noselect (car pos))))))
|
||||||
|
(with-current-buffer (marker-buffer m)
|
||||||
|
(org-with-point-at m
|
||||||
|
(cond
|
||||||
|
;; Priority 1: Use actual CLOSED timestamp if DONE
|
||||||
|
((org-entry-get nil "CLOSED")
|
||||||
|
(org-time-string-to-time (org-entry-get nil "CLOSED")))
|
||||||
|
;; Priority 2: Use range end if FIXED
|
||||||
|
((string-equal "t" (org-entry-get nil "FIXED"))
|
||||||
|
(gortium/org--get-range-end m))
|
||||||
|
;; Priority 3: Fallback to existing range end if it exists
|
||||||
|
((gortium/org--get-range-end m)
|
||||||
|
(gortium/org--get-range-end m))
|
||||||
|
(t nil))))))
|
||||||
|
(t nil)))
|
||||||
|
|
||||||
|
;; 2. Update the "Latest" tracker
|
||||||
|
(if blocker-end
|
||||||
|
(when (or (null latest-time) (time-less-p latest-time blocker-end))
|
||||||
|
(setq latest-time blocker-end))
|
||||||
|
;; If ANY blocker is not resolved/found, the whole task is not ready
|
||||||
|
(setq all-resolved nil)))))
|
||||||
|
|
||||||
|
;; Only return a time if EVERY ID in the list was successfully resolved
|
||||||
|
(when all-resolved latest-time)))
|
||||||
|
|
||||||
|
(defun gortium/internal--update-properties (pos start wknd id end task-end-map)
|
||||||
|
"Heals the property drawer, updates values, and fixes vertical spacing without leaking newlines."
|
||||||
|
(message "[DEBUG] enter update-properties for %s" id)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char pos)
|
||||||
|
(org-back-to-heading t)
|
||||||
|
(let* ((subtree-start (point))
|
||||||
|
(subtree-end (save-excursion (org-end-of-subtree t) (point))))
|
||||||
|
|
||||||
|
(save-restriction
|
||||||
|
(narrow-to-region subtree-start subtree-end)
|
||||||
|
|
||||||
|
;; --- STEP 1: HEAL THE DRAWER ---
|
||||||
|
(goto-char (point-min))
|
||||||
|
(forward-line 1)
|
||||||
|
(while (looking-at "^[ \t]*\\(CLOSED:\\|SCHEDULED:\\|DEADLINE:\\)")
|
||||||
|
(forward-line 1))
|
||||||
|
|
||||||
|
(when (looking-at "^[ \t]*:PROPERTIES:[ \t]*$")
|
||||||
|
(let ((drawer-start (point)))
|
||||||
|
(when (re-search-forward "^[ \t]*:END:[ \t]*$" nil t)
|
||||||
|
(let ((drawer-end (match-end 0)))
|
||||||
|
(save-restriction
|
||||||
|
(narrow-to-region drawer-start drawer-end)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(forward-line 1)
|
||||||
|
(while (re-search-forward "^[ \t]*$" nil t)
|
||||||
|
(delete-region (line-beginning-position)
|
||||||
|
(min (1+ (line-end-position)) (point-max)))))))))
|
||||||
|
|
||||||
|
;; --- STEP 2: UPDATE PROPERTY ---
|
||||||
|
(org-entry-put nil "WEEKEND_DAYS" (number-to-string (or wknd 0)))
|
||||||
|
|
||||||
|
;; --- STEP 3: REMOVE OLD RANGE ---
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward "^[ \t]*<.+>--<.+>[ \t]*\n?" nil t)
|
||||||
|
(replace-match ""))
|
||||||
|
|
||||||
|
;; --- STEP 4: FIND INSERTION POINT ---
|
||||||
|
(goto-char (point-min))
|
||||||
|
(forward-line 1)
|
||||||
|
(while (looking-at "^[ \t]*\\(CLOSED:\\|SCHEDULED:\\|DEADLINE:\\)")
|
||||||
|
(forward-line 1))
|
||||||
|
(while (looking-at "^[ \t]*:\\([A-Z_]+\\):[ \t]*$")
|
||||||
|
(when (re-search-forward "^[ \t]*:END:[ \t]*$" nil t)
|
||||||
|
(forward-line 1)))
|
||||||
|
|
||||||
|
;; Delete any existing blank lines at the insertion point
|
||||||
|
(while (and (looking-at "^[ \t]*$") (not (eobp)))
|
||||||
|
(delete-region (line-beginning-position) (line-beginning-position 2)))
|
||||||
|
|
||||||
|
;; --- STEP 5: INSERT RANGE ---
|
||||||
|
;; Ensure range starts on a new line and ends with exactly one newline
|
||||||
|
(unless (bolp) (insert "\n"))
|
||||||
|
(insert (format "<%s>--<%s>\n"
|
||||||
|
(format-time-string "%Y-%m-%d %a %H:%M" start)
|
||||||
|
(format-time-string "%Y-%m-%d %a %H:%M" end)))
|
||||||
|
|
||||||
|
;; --- STEP 6: CLEAN UP REMAINING WHITESPACE WITHIN TASK ---
|
||||||
|
(while (and (looking-at "^[ \t]*$") (not (eobp)))
|
||||||
|
(delete-region (line-beginning-position) (line-beginning-position 2))))
|
||||||
|
|
||||||
|
;; --- STEP 7: NORMALIZE SPACING BETWEEN TASKS ---
|
||||||
|
;; Instead of inserting a newline blindly, we ensure exactly one blank line
|
||||||
|
;; exists between this subtree's end and the next heading.
|
||||||
|
(goto-char (org-end-of-subtree t))
|
||||||
|
(let ((post-subtree (point)))
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(goto-char post-subtree)
|
||||||
|
(delete-blank-lines)
|
||||||
|
;; Only insert a blank line if we aren't at the end of the buffer
|
||||||
|
(unless (eobp)
|
||||||
|
(insert "\n")))))
|
||||||
|
|
||||||
|
(message "[DEBUG] exit update-properties")
|
||||||
|
(puthash id end task-end-map)))
|
||||||
|
|
||||||
|
;; ------------------------------------------------------------
|
||||||
|
;; Helper: Detect circular dependencies
|
||||||
|
;; ------------------------------------------------------------
|
||||||
|
(defun gortium/internal--detect-circular-deps (tasks)
|
||||||
|
"Check for circular dependencies in TASKS.
|
||||||
|
Returns list of task IDs involved in cycles, or nil if no cycles found."
|
||||||
|
(let ((graph (make-hash-table :test 'equal))
|
||||||
|
(visiting (make-hash-table :test 'equal))
|
||||||
|
(visited (make-hash-table :test 'equal))
|
||||||
|
(cycles nil))
|
||||||
|
|
||||||
|
;; Build dependency graph
|
||||||
|
(dolist (task tasks)
|
||||||
|
(pcase-let ((`(,_pos ,id ,_effort ,blocker ,_fixed ,_sched ,_rng-start ,_offset ,_state) task))
|
||||||
|
(when (and blocker (not (string-empty-p (s-trim blocker))))
|
||||||
|
(when (string-match "ids(\\(.*?\\))" blocker)
|
||||||
|
(let ((deps (split-string (match-string 1 blocker) "[ ,]+" t)))
|
||||||
|
(puthash id (mapcar (lambda (tid)
|
||||||
|
(replace-regexp-in-string "[\"']\\|id:" "" tid))
|
||||||
|
deps)
|
||||||
|
graph))))))
|
||||||
|
|
||||||
|
;; DFS to detect cycles
|
||||||
|
(cl-labels ((dfs (node path)
|
||||||
|
(cond
|
||||||
|
((gethash node visiting)
|
||||||
|
;; Found a cycle
|
||||||
|
(push node cycles)
|
||||||
|
t)
|
||||||
|
((gethash node visited)
|
||||||
|
nil)
|
||||||
|
(t
|
||||||
|
(puthash node t visiting)
|
||||||
|
(dolist (dep (gethash node graph))
|
||||||
|
(when (dfs dep (cons node path))
|
||||||
|
(push node cycles)))
|
||||||
|
(remhash node visiting)
|
||||||
|
(puthash node t visited)
|
||||||
|
nil))))
|
||||||
|
|
||||||
|
(maphash (lambda (node _deps)
|
||||||
|
(unless (gethash node visited)
|
||||||
|
(dfs node nil)))
|
||||||
|
graph))
|
||||||
|
|
||||||
|
(delete-dups cycles)))
|
||||||
|
|
||||||
|
(advice-add 'org-roam-db-sync :before
|
||||||
|
(lambda (&rest _)
|
||||||
|
(message "[DEBUG] org-roam-db-sync invoked")))
|
||||||
|
|
||||||
|
;; --- MAIN SCHEDULER ---
|
||||||
|
(defun gortium/org-schedule-subtree-chains ()
|
||||||
|
"Standard Gortium scheduler: Correctly calculates Finish-to-Start dependencies."
|
||||||
|
(interactive)
|
||||||
|
(message "=== Starting Gortium Scheduler ===")
|
||||||
|
|
||||||
|
(let ((all-tasks '())
|
||||||
|
(task-end-times (make-hash-table :test 'equal))
|
||||||
|
(start-time (current-time))
|
||||||
|
(org-element-use-cache nil)) ;; Disable buggy cache
|
||||||
|
|
||||||
|
;; 1. COLLECT
|
||||||
|
(org-map-entries
|
||||||
|
(lambda ()
|
||||||
|
(when (org-get-todo-state)
|
||||||
|
(let* ((pos (point-marker))
|
||||||
|
(id (or (org-id-get) (org-id-get-create))))
|
||||||
|
(push (list (current-buffer) pos id
|
||||||
|
(org-entry-get pos "EFFORT")
|
||||||
|
(org-entry-get pos "BLOCKER")
|
||||||
|
(org-entry-get pos "FIXED")
|
||||||
|
(org-get-scheduled-time pos)
|
||||||
|
(org-entry-get pos "OFFSET_DAYS"))
|
||||||
|
all-tasks))))
|
||||||
|
nil nil)
|
||||||
|
|
||||||
|
(setq all-tasks (nreverse all-tasks))
|
||||||
|
|
||||||
|
;; 2. ITERATE
|
||||||
|
(let* ((remaining all-tasks)
|
||||||
|
(limit (* 20 (length remaining)))
|
||||||
|
(iter 0))
|
||||||
|
|
||||||
;; Pass 2: CHAINS
|
|
||||||
(let* ((remaining (cl-remove-if (lambda (tk) (or (nth 5 tk) (not (nth 4 tk)))) all-tasks))
|
|
||||||
(iter 0) (limit (* 5 (length all-tasks))))
|
|
||||||
(while (and remaining (< iter limit))
|
(while (and remaining (< iter limit))
|
||||||
(cl-incf iter)
|
(setq iter (1+ iter))
|
||||||
(let ((scheduled-this-loop '()))
|
(let ((done-this-loop '()))
|
||||||
(dolist (task remaining)
|
(dolist (task remaining)
|
||||||
(pcase-let ((`(,pos ,id ,heading ,effort ,blocker ,fixed ,scheduled ,offset) task))
|
(pcase-let ((`(,buf ,pos ,id ,effort ,blocker ,fixed ,sched ,offset) task))
|
||||||
(let ((dep-end (gortium/internal--get-blocker-end blocker pos task-end-times)))
|
(let* ((blocker-end (gortium/internal--get-blocker-end blocker task-end-times))
|
||||||
(when dep-end
|
(has-blocker (and blocker (not (string-empty-p (s-trim blocker)))))
|
||||||
(let* ((off-val (if offset (string-to-number offset) 0))
|
(is-fixed (string-equal fixed "t"))
|
||||||
(base-start (time-add dep-end (days-to-time off-val)))
|
(ready (or is-fixed (not has-blocker) blocker-end)))
|
||||||
(start (gortium/internal--snap-to-working-hours base-start))
|
|
||||||
(span (gortium/internal--calculate-task-span start effort)))
|
|
||||||
(gortium/internal--update-properties pos start (cadr span) id (car span) task-end-times)
|
|
||||||
(push task scheduled-this-loop))))))
|
|
||||||
(setq remaining (cl-remove-if (lambda (tk) (member tk scheduled-this-loop)) remaining))))
|
|
||||||
|
|
||||||
(dolist (task all-tasks) (set-marker (car task) nil)) ;; Clean markers
|
(when ready
|
||||||
(message "--- Scheduler Finished ---")))))
|
(with-current-buffer buf
|
||||||
|
(org-element-with-disabled-cache
|
||||||
|
(let* ((off-days (if (stringp offset) (string-to-number offset) 0))
|
||||||
|
(base-start (cond
|
||||||
|
;; 1. If FIXED, use its own defined start
|
||||||
|
(is-fixed (or (gortium/org--get-range-start pos) sched (current-time)))
|
||||||
|
;; 2. If it HAS a blocker, it MUST use blocker-end.
|
||||||
|
;; If blocker-end is nil, this task isn't 'ready' yet.
|
||||||
|
(has-blocker blocker-end)
|
||||||
|
;; 3. If no blocker and not fixed, use current schedule or now
|
||||||
|
(t (or sched (current-time)))))
|
||||||
|
|
||||||
;; USAGE:
|
(final-start (if is-fixed base-start
|
||||||
;; 1. Set up your tasks with either:
|
(gortium/internal--snap-to-working-hours
|
||||||
;; - :FIXED: t and a SCHEDULED date, OR
|
(time-add base-start (days-to-time off-days)))))
|
||||||
;; - :BLOCKER: previous-sibling / ids(UUID) / ids("id:UUID") / parent
|
|
||||||
;; 2. Put cursor on "Planning" heading
|
(span (gortium/internal--calculate-task-span final-start effort))
|
||||||
;; 3. M-x gortium/org-schedule-subtree-chains
|
(final-end (car span))
|
||||||
;;
|
(wknd (cadr span)))
|
||||||
;; The function will:
|
|
||||||
;; - Use FIXED tasks as anchors
|
(gortium/internal--update-properties pos final-start wknd id final-end task-end-times)
|
||||||
;; - Calculate all other tasks from their dependencies
|
(push task done-this-loop))))))))
|
||||||
;; - Warn about tasks without BLOCKER or FIXED
|
(setq remaining (cl-set-difference remaining done-this-loop))))
|
||||||
;; - Detect circular dependencies
|
|
||||||
;; - Respect 8-hour workday limits
|
;; --- DIAGNOSTICS FOR UNSCHEDULED TASKS ---
|
||||||
;; - Skip weekends
|
(if remaining
|
||||||
;;
|
(progn
|
||||||
;; Supported BLOCKER types (standard EDNA format):
|
(message "!!! WARNING: %d tasks were NOT scheduled !!!" (length remaining))
|
||||||
;; - previous-sibling
|
(dolist (task remaining)
|
||||||
;; - ids(UUID) - e.g., ids(70d8f844-1952-43f0-8043-da51e8c8bc69)
|
(pcase-let ((`(,_buf ,pos ,id ,_eff ,blocker ,_fix ,_sch ,_off) task))
|
||||||
;; - ids("id:UUID") - e.g., ids("id:70d8f844-1952-43f0-8043-da51e8c8bc69")
|
(let* ((blocker-string (format "%s" blocker))
|
||||||
;; - parent
|
(clean-blocker (if (string-match "ids(\\(.*?\\))" blocker-string)
|
||||||
|
(match-string 1 blocker-string)
|
||||||
|
"None")))
|
||||||
|
(message " -> Task [%s] at pos %s is BLOCKED by: %s"
|
||||||
|
id (marker-position pos) clean-blocker)))))
|
||||||
|
(message "=== All tasks scheduled successfully! ==="))
|
||||||
|
|
||||||
|
;; 3. CLEANUP
|
||||||
|
(setq org-element-use-cache t)
|
||||||
|
(org-element-cache-reset 'all)
|
||||||
|
(message "=== Scheduler completed (%d tasks, %d iterations) ===" (length all-tasks) iter)
|
||||||
|
;; (gortium/org-rollup-parent-ranges)
|
||||||
|
;; (message "=== All Scheduling and Roll-ups Complete ===")
|
||||||
|
)))
|
||||||
|
|
||||||
|
;; ---------------------------------------------
|
||||||
|
(defun gortium/org-ensure-task-properties ()
|
||||||
|
"Iterate through all tasks (TODO, NEXT, STRT, WAIT, HOLD, DONE, etc.)
|
||||||
|
and ensure the standard property drawer exists without overwriting existing data."
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(message "--- Initializing Task Properties for all states ---")
|
||||||
|
(let ((count 0)
|
||||||
|
;; List of properties to ensure exist
|
||||||
|
(props '("EFFORT" "BLOCKER" "FIXED" "WEEKEND_DAYS"
|
||||||
|
"ASSIGNEE" "RESOURCES" "CATEGORY"
|
||||||
|
"DIMENTIONS" "WEIGHT" "OFFSET_DAYS")))
|
||||||
|
(org-map-entries
|
||||||
|
(lambda ()
|
||||||
|
;; This check returns true if the heading has ANY todo keyword
|
||||||
|
(let ((todo-state (org-get-todo-state)))
|
||||||
|
(when todo-state
|
||||||
|
(cl-incf count)
|
||||||
|
;; 1. Handle ID (builtin handles 'do not replace' logic)
|
||||||
|
(org-id-get-create)
|
||||||
|
|
||||||
|
;; 2. Ensure all other keys exist
|
||||||
|
(dolist (prop props)
|
||||||
|
;; Only add the property if it's currently nil/missing
|
||||||
|
(unless (org-entry-get (point) prop)
|
||||||
|
(org-entry-put (point) prop
|
||||||
|
(if (string= prop "FIXED") "nil" "")))))))
|
||||||
|
nil nil)
|
||||||
|
(message "--- Finished: Processed %d tasks across all states ---" count))))
|
||||||
|
|
||||||
(defun gortium/add-ids-to-subtree ()
|
(defun gortium/add-ids-to-subtree ()
|
||||||
"Add IDs to all headings in current subtree."
|
"Add IDs to all headings in current subtree."
|
||||||
@@ -1760,20 +1821,6 @@ Otherwise, use SCHEDULED + EFFORT."
|
|||||||
(lambda () (org-id-get-create))
|
(lambda () (org-id-get-create))
|
||||||
nil 'tree)))
|
nil 'tree)))
|
||||||
|
|
||||||
;; Custom function to shift projects
|
|
||||||
(defun gortium/org-shift-subtree-schedules (days)
|
|
||||||
"Shift all SCHEDULED dates in the current subtree by DAYS."
|
|
||||||
(interactive "nDays to shift: ")
|
|
||||||
(org-map-entries
|
|
||||||
(lambda ()
|
|
||||||
(let ((scheduled (org-entry-get nil "SCHEDULED")))
|
|
||||||
(when scheduled
|
|
||||||
(let* ((time (org-time-string-to-time scheduled))
|
|
||||||
(new-time (time-add time (days-to-time days)))
|
|
||||||
(new-date (format-time-string (org-time-stamp-format) new-time)))
|
|
||||||
(org-entry-put nil "SCHEDULED" new-date)))))
|
|
||||||
nil 'tree))
|
|
||||||
|
|
||||||
;; Open link in another frame
|
;; Open link in another frame
|
||||||
(defun gortium/org-open-link-in-other-frame ()
|
(defun gortium/org-open-link-in-other-frame ()
|
||||||
"Open the Org link at point in another frame."
|
"Open the Org link at point in another frame."
|
||||||
@@ -1960,13 +2007,3 @@ fallback to today's daily note. Ensures the daily has an Org-roam ID."
|
|||||||
(message "Task refiled under '%s' in %s"
|
(message "Task refiled under '%s' in %s"
|
||||||
headline
|
headline
|
||||||
(file-name-nondirectory daily-file)))))
|
(file-name-nondirectory daily-file)))))
|
||||||
|
|
||||||
;; Org-edna for advanced task dependencies
|
|
||||||
(use-package! org-edna
|
|
||||||
:after org
|
|
||||||
:config
|
|
||||||
(setq org-edna-use-inheritance t)
|
|
||||||
(org-edna-mode 1)
|
|
||||||
(map! :map org-mode-map
|
|
||||||
:localleader
|
|
||||||
:desc "Edit Edna rules" "E" #'org-edna-edit))
|
|
||||||
|
|||||||
@@ -150,7 +150,9 @@
|
|||||||
;;lean ; for folks with too much to prove
|
;;lean ; for folks with too much to prove
|
||||||
ledger ; be audit you can be
|
ledger ; be audit you can be
|
||||||
lua ; one-based indices? one-based indices
|
lua ; one-based indices? one-based indices
|
||||||
markdown ; writing docs for people to ignore
|
(markdown ; writing docs for people to ignore
|
||||||
|
+grip
|
||||||
|
+tree-sitter)
|
||||||
;;nim ; python + lisp at the speed of c
|
;;nim ; python + lisp at the speed of c
|
||||||
(nix ; I hereby declare "nix geht mehr!"
|
(nix ; I hereby declare "nix geht mehr!"
|
||||||
+lsp
|
+lsp
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ env = WLR_RENDERER_ALLOW_SOFTWARE,1
|
|||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#general
|
# https://wiki.hyprland.org/Configuring/Variables/#general
|
||||||
general {
|
general {
|
||||||
gaps_in = 4.5
|
gaps_in = 7.5
|
||||||
gaps_out = 9
|
gaps_out = 15
|
||||||
|
|
||||||
border_size = 2
|
border_size = 2
|
||||||
|
|
||||||
@@ -148,7 +148,12 @@ animations {
|
|||||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
||||||
dwindle {
|
dwindle {
|
||||||
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
||||||
|
|
||||||
|
# This prevents the layout from collapsing if you close one window
|
||||||
preserve_split = true # You probably want this
|
preserve_split = true # You probably want this
|
||||||
|
|
||||||
|
# 0 -> follow mouse, 1 -> always left/top, 2 -> always right/bottom
|
||||||
|
force_split = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
|
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
|
||||||
@@ -219,8 +224,8 @@ bind = $mainMod, P, togglesplit, # dwindle
|
|||||||
bind = $mainMod, N, movecurrentworkspacetomonitor, -1
|
bind = $mainMod, N, movecurrentworkspacetomonitor, -1
|
||||||
bind = $mainMod SHIFT, N, movecurrentworkspacetomonitor, +1
|
bind = $mainMod SHIFT, N, movecurrentworkspacetomonitor, +1
|
||||||
bind = $mainMod, X, swapwindow
|
bind = $mainMod, X, swapwindow
|
||||||
bind = $mainMod, B, exec, nerd-dictation begin
|
bind = $mainMod, B, exec, python /home/tpouplier/ExoKortex/1-Projects/Perso/recordntrans/record_transcribe.py
|
||||||
bind = $mainMod, G, exec, nerd-dictation end
|
# bind = $mainMod, G, exec, nerd-dictation end
|
||||||
bind = $mainMod, A, exec, $music
|
bind = $mainMod, A, exec, $music
|
||||||
|
|
||||||
# Full screen
|
# Full screen
|
||||||
@@ -287,8 +292,8 @@ bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
|||||||
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
||||||
|
|
||||||
# Example special workspace (scratchpad)
|
# Example special workspace (scratchpad)
|
||||||
bind = $mainMod, S, togglespecialworkspace, magic
|
bind = $mainMod, S, togglespecialworkspace, tools
|
||||||
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
|
bind = $mainMod SHIFT, S, movetoworkspace, special:tools
|
||||||
|
|
||||||
# Scroll through existing workspaces with mainMod + scroll
|
# Scroll through existing workspaces with mainMod + scroll
|
||||||
bind = $mainMod, mouse_down, workspace, e+1
|
bind = $mainMod, mouse_down, workspace, e+1
|
||||||
@@ -376,4 +381,42 @@ workspace = 3, name:long-1, monitor:DP-5 # Right screen
|
|||||||
workspace = 4, name:long-2, monitor:DP-5 # Right screen
|
workspace = 4, name:long-2, monitor:DP-5 # Right screen
|
||||||
workspace = 5, name:smoll, monitor:eDP-1 # Laptop screen
|
workspace = 5, name:smoll, monitor:eDP-1 # Laptop screen
|
||||||
#workspace = 4, name:windows, monitor:DP-4, on-created-empty:VBoxManage startvm "Windows 11"
|
#workspace = 4, name:windows, monitor:DP-4, on-created-empty:VBoxManage startvm "Windows 11"
|
||||||
#workspace = special:scratchpad, on-created-empty:kitty
|
workspace = special:tools, layout:dwindle, gapsin:0
|
||||||
|
|
||||||
|
# Top Left: btop
|
||||||
|
windowrule {
|
||||||
|
name = dashboard-btop
|
||||||
|
match:class = ^(btop)$
|
||||||
|
tile = true
|
||||||
|
workspace = special:tools
|
||||||
|
}
|
||||||
|
|
||||||
|
# Top Right: ncspot
|
||||||
|
windowrule {
|
||||||
|
name = dashboard-ncspot
|
||||||
|
match:class = ^(ncspot)$
|
||||||
|
tile = true
|
||||||
|
workspace = special:tools
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bottom Left: ncpamixer
|
||||||
|
windowrule {
|
||||||
|
name = dashboard-ncpamixer
|
||||||
|
match:class = ^(ncpamixer)$
|
||||||
|
tile = true
|
||||||
|
workspace = special:tools
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bottom Right: bluetuith
|
||||||
|
windowrule {
|
||||||
|
name = dashboard-bluetuith
|
||||||
|
match:class = ^(bluetuith)$
|
||||||
|
tile = true
|
||||||
|
workspace = special:tools
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bind to launch the suite (Run this once)
|
||||||
|
bind = $mainMod, grave, exec, kitty --class btop btop
|
||||||
|
bind = $mainMod, grave, exec, kitty --class ncspot ncspot
|
||||||
|
bind = $mainMod, grave, exec, kitty --class ncpamixer ncpamixer
|
||||||
|
bind = $mainMod, grave, exec, kitty --class bluetuith bluetuith
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
// general settings
|
// general settings
|
||||||
"position": "top",
|
"position": "top",
|
||||||
"margin-top": 8,
|
"margin-top": 15,
|
||||||
"margin-bottom": 0,
|
"margin-bottom": 0,
|
||||||
"layer": "top",
|
"layer": "top",
|
||||||
"margin-left": 8,
|
"margin-left": 15,
|
||||||
"margin-right": 8,
|
"margin-right": 15,
|
||||||
"spacing": 10,
|
"spacing": 10,
|
||||||
"fixed-center": true,
|
"fixed-center": true,
|
||||||
"exclusive": true,
|
"exclusive": true,
|
||||||
|
|||||||
@@ -110,7 +110,7 @@
|
|||||||
"car": "",
|
"car": "",
|
||||||
"default": ["", "", ""]
|
"default": ["", "", ""]
|
||||||
},
|
},
|
||||||
"on-click": "pwvucontrol"
|
"on-click": "kitty ncpamixer"
|
||||||
},
|
},
|
||||||
|
|
||||||
// bluetooth
|
// bluetooth
|
||||||
|
|||||||
@@ -125,3 +125,6 @@ export HYPRSHOT_DIR="Images"
|
|||||||
# Atuin
|
# Atuin
|
||||||
#eval "$(atuin init zsh)"
|
#eval "$(atuin init zsh)"
|
||||||
|
|
||||||
|
|
||||||
|
# Created by `pipx` on 2026-03-03 16:51:31
|
||||||
|
export PATH="$PATH:/home/tpouplier/.local/bin"
|
||||||
|
|||||||
Reference in New Issue
Block a user