Compare commits

..

No commits in common. "ee6a9b405e6fc20fafb50451c34288aa0c27ed50" and "d7ce49727819330e34a9203c2dbbef84023a1646" have entirely different histories.

12 changed files with 710 additions and 146 deletions

167
bin/ical2org Executable file
View File

@ -0,0 +1,167 @@
#!/usr/bin/env perl
# by PerlStalker, http://perlstalker.vuser.org/blog/2014/06/04/importing-ical-into-org-mode/
# with minor modifications by exot
use warnings;
use strict;
use Data::ICal;
use Data::Dumper;
use DateTime::Format::ICal;
use Getopt::Long;
my $category = undef;
my $filetags = undef;
GetOptions(
'category|c=s' => \$category,
'filetags|f=s' => \$filetags
);
my $cal = Data::ICal->new(data => join '', <STDIN>);
#print Dumper $cal;
my %gprops = %{ $cal->properties };
print "#+TITLE: ical entries\n";
print "#+AUTHOR: ".$gprops{'x-wr-calname'}[0]->decoded_value."\n" if defined $gprops{'x-wr-calname'};
print "#+EMAIL: \n";
print "#+DESCRIPTION: Converted using ical2org.pl\n";
print "#+CATEGORY: $category\n" if defined($category);
print "#+FILETAGS: $filetags\n" if defined($filetags);
print "#+STARTUP: overview\n";
print "\n";
#print "* COMMENT original iCal properties\n";
#print Dumper \%gprops;
#print "Timezone: ", $gprops{'x-wr-timezone'}[0]->value, "\n";
#foreach my $prop (values %gprops) {
# foreach my $p (@{ $prop }) {
# print $p->key, ':', $p->value, "\n";
# }
#}
my $error_code = 0;
foreach my $entry (@{ $cal->entries }) {
next if not $entry->isa('Data::ICal::Entry::Event');
# print 'Entry: ', Dumper $entry;
eval { handle_entry($entry) };
if ($@) {
print STDERR $@;
$error_code = 1;
}
}
exit $error_code;
sub org_date_range {
my $start = shift;
my $end = shift;
my $str = sprintf('<%04d-%02d-%02d %s %02d:%02d>',
$start->year,
$start->month,
$start->day,
$start->day_abbr,
$start->hour,
$start->minute
);
$str .= '--';
$str .= sprintf('<%04d-%02d-%02d %s %02d:%02d>',
$end->year,
$end->month,
$end->day,
$end->day_abbr,
$end->hour,
$end->minute
);
return $str;
}
sub handle_entry {
my $entry = shift;
my %props = %{ $entry->properties };
# skip entries with no start
next if not $props{dtstart}[0];
my $dtstart = DateTime::Format::ICal->parse_datetime($props{dtstart}[0]->value);
my ($duration, $dtend);
if (not $props{dtend}[0]) {
$duration = DateTime::Format::ICal->parse_duration($props{duration}[0]->value);
$dtend = $dtstart->clone->add_duration($duration);
} else {
$dtend = DateTime::Format::ICal->parse_datetime($props{dtend}[0]->value);
$duration = $dtend->subtract_datetime($dtstart);
}
if (defined $props{rrule}) {
#print " REPEATABLE\n";
# Bad: There may be multiple rrules but I'm ignoring them
my $set = DateTime::Format::ICal->parse_recurrence(recurrence => $props{rrule}[0]->value,
dtstart => $dtstart,
dtend => DateTime->now->add(weeks => 1),
);
my $itr = $set->iterator;
while (my $dt = $itr->next) {
$dt->set_time_zone($props{dtstart}[0]->parameters->{'TZID'} || $gprops{'x-wr-timezone'}[0]->value);
print "* ".$props{summary}[0]->decoded_value."\n";
my $end = $dt->clone->add_duration($duration);
print ' ', org_date_range($dt, $end), "\n";
#print $dt, "\n";
print " :PROPERTIES:\n";
printf " :ID: %s\n", $props{uid}[0]->value;
if (defined $props{location}) {
printf " :LOCATION: %s\n", $props{location}[0]->value;
}
if (defined $props{status}) {
printf " :STATUS: %s\n", $props{status}[0]->value;
}
print " :END:\n";
if ($props{description}) {
print "\n", $props{description}[0]->decoded_value, "\n";
}
}
}
else {
print "* ".$props{summary}[0]->decoded_value."\n";
# my $tz = $gprops{'x-wr-timezone'}[0]->value;
# $dtstart->set_time_zone($props{dtstart}[0]->parameters->{'TZID'} || $tz);
# $dtend->set_time_zone($props{dtend}[0]->parameters->{'TZID'} || $tz);
print ' ', org_date_range($dtstart, $dtend), "\n";
print " :PROPERTIES:\n";
printf " :ID: %s\n", $props{uid}[0]->value;
if (defined $props{location}) {
printf " :LOCATION: %s\n", $props{location}[0]->value;
}
if (defined $props{status}) {
printf " :STATUS: %s\n", $props{status}[0]->value;
}
print " :END:\n";
if ($props{description}) {
print "\n", $props{description}[0]->decoded_value, "\n";
}
}
# print Dumper \%props;
}

426
bin/ical2org.awk Executable file
View File

@ -0,0 +1,426 @@
# awk script for converting an iCal formatted file to a sequence of org-mode headings.
# this may not work in general but seems to work for day and timed events from Google's
# calendar, which is really all I need right now...
#
# usage:
# awk -f THISFILE < icalinputfile.ics > orgmodeentries.org --assign NAME=category
#
# where the category is used to define a CATEGORY for all entries in
# the file and also assign that label as a tag to each entry
#
# Note: change org meta information generated below for author and
# email entries!
#
# Known bugs:
# - not so much a bug as a possible assumption: date entries with no time
# specified are assumed to be independent of the time zone.
#
# Eric S Fraga
# 20100629 - initial version
# 20100708 - added end times to timed events
# - adjust times according to time zone information
# - fixed incorrect transfer for entries with ":" embedded within the text
# - added support for multi-line summary entries (which become headlines)
# 20100709 - incorporated time zone identification
# - fixed processing of continuation lines as Google seems to
# have changed, in the last day, the number of spaces at
# the start of the line for each continuation...
# - remove backslashes used to protect commas in iCal text entries
# no further revision log after this as the file was moved into a git
# repository...
#
# Last change: 2016.05.26 08:47:12
#----------------------------------------------------------------------------------
# a function to take the iCal formatted date+time, convert it into an
# internal form (seconds since time 0), and adjust according to the
# local time zone (specified by +-seconds calculated in the BEGIN
# section)
function datetimestamp(input)
{
# convert the iCal Date+Time entry to a format that mktime can understand
datespec = gensub("([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])T([0-9][0-9])([0-9][0-9])([0-9][0-9]).*[\r]*", "\\1 \\2 \\3 \\4 \\5 \\6", "g", input);
# print "date spec : " datespec; convert this date+time into
# seconds from the beginning of time and include adjustment for
# time zone, as determined in the BEGIN section below. The
# adjustment is only included if the time stamp has a Z at the
# end. Of course, we should actually incorporate the time zone
# information in the time stamp line but ...
if (0 < index(input,"Z")) {
# For time
# zone adjustment, I have not tested edge effects, specifically
# what happens when UTC time is a different day to local time and
# especially when an event with a duration crosses midnight in UTC
# time. It should work but...
timestamp = mktime(datespec) + seconds;
}
else {
timestamp = mktime(datespec);
}
# print "date spec: " datespec;
#timestamp = mktime(datespec);
# print "adjusted : " timestamp
# print "Time stamp : " strftime("%Y-%m-%d %H:%M", timestamp);
return timestamp;
}
# version of above but for dates only
function datestamp(input)
{
# create a date using midnight as the time
datespec = gensub( "([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9]).*[\r]*", "\\1 \\2 \\3 0 0 0", "g", input );
# convert to internal representation
timestamp = mktime(datespec);
# and finally convert to something org understands
datestring = strftime("%Y-%m-%d %a", timestamp);
#print "In datestamp: datespec=" datespec " timestamp=" timestamp " datestring=" datestring;
return datestring;
}
# start of the output file now
BEGIN {
# use a colon to separate the type of data line from the actual contents
FS = ":";
# determine the number of seconds to use for adjusting for time
# zone difference from UTC. This is used in the function
# datetimestamp above. The time zone information returned by
# strftime() is in hours * 100 so we multiply by 36 to get
# seconds. This does not work for time zones that are not an
# integral multiple of hours (e.g. Newfoundland)
seconds = gensub("([+-])0", "\\1", 1, strftime("%z")) * 36;
date1 = ""; # for start of an event
date2 = ""; # for end of an event, if specified
entry = ""
first = 1; # true until an event has been found
headline = ""
icalentry = "" # the full entry for inspection
id = ""
indescription = 0;
inevent = 0; # we have VEVENTS but also other items which we do not process
location = ""; # outlook entries, at least, often include a location
repeat = ""; # is item repeated? if so, how often
time1 = ""; # for start of an event, if specified
time2 = ""; # for end of an event, if specified
todotype = ""; # type of TODO
if (NAME == "")
NAME = "ical2org";
print "# -*- mode: auto-revert; mode: org; -*-" # suggested by Henrik Holmboe
print "#+TITLE: Main Google calendar entries"
print "#+AUTHOR: Eric S Fraga"
print "#+EMAIL: e.fraga@ucl.ac.uk"
print "#+DESCRIPTION: converted using the ical2org awk script"
print "#+CATEGORY: " NAME
print " "
}
# continuation lines (at least from Google) start with two spaces
# if the continuation is after a description or a summary, append the entry
# to the respective variable
/^[ ]+/ {
if (indescription) {
entry = entry gensub("\r", "", "g", gensub("^[ ]+", "", 1, $0));
} else if (insummary) {
summary = summary gensub("\r", "", "g", gensub("^[ ]+", "", 1, $0))
} else if (inuid) {
id = id gensub("\r", "", "g", gensub("^[ ]+", "", 1, $0))
}
icalentry = icalentry "\n" $0
}
/^BEGIN:VEVENT/ {
# start of an event. if this is the first, output the preamble from the iCal file
if (first) {
print "* COMMENT original iCal preamble"
print gensub("\r", "", "g", icalentry)
icalentry = ""
}
havesummary = 0;
inevent = 1;
first = false;
repeat = "";
}
/^BEGIN:VTODO/ {
if (first){
print "* COMMENT original iCal preamble";
print gensub("\r", "", "g", icalentry);
icalentry = "";
first = false;
}
havesummary = 0;
intodo = 1;
repeat = "";
todotype = "";
}
# any line that starts at the left with a non-space character is a new data field
/^[A-Z]/ {
# we ignore DTSTAMP lines as they change every time you download
# the iCal format file which leads to a change in the converted
# org file as I output the original input. This change, which is
# really content free, makes a revision control system update the
# repository and confuses.
if (! index("DTSTAMP", $1)) icalentry = icalentry "\n" $0
# this line terminates the collection of description and summary entries
indescription = 0;
if (insummary) {
havesummary = 1;
}
insummary = 0;
}
# this type of entry represents a day entry, not timed, with date
# stamp YYYYMMDD. For a todo item, this indicates a scheduled item.
/^DTSTART;VALUE=DATE/ {
# print "DTSTART date only entry: " $0;
# date1 = gensub("([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9]).*[\r]*", "\\1-\\2-\\3", "g", $2)
date1 = datestamp($2);
time1 = ""
}
# this represents a timed entry with date and time stamp
# YYYYMMDDTHHMMSS we ignore the seconds. This entry may have a time
# zone specification which is currently ignored although it should be
# possible, not easy, to incorporate. We assume that this information
# is only relevant for appointments and not TODO items. We expect
# TODO items to have only a date for the START field and that date
# will be the scheduled date. See above.
/^DTSTART(;TZID.*)?:/ {
if (inevent) {
# print "DTSTART line: " $0;
# print "checking start time: " $2;
date1 = strftime("%Y-%m-%d %a", datetimestamp($2));
time1 = strftime(" %H:%M", datetimestamp($2));
# print "====> time: " time1;
# print date;
}
}
# and the same for the end date; here we extract only the time and append this to the
# date+time found by the DTSTART entry. We assume that entry was there, of course.
# should probably add some error checking here! In time...
/^DTEND;VALUE=DATE/ {
if (inevent) {
# date2 = gensub("([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9]).*[\r]", "\\1-\\2-\\3", "g", $2)
date2 = datestamp($2);
time2 = ""
}
}
/^DTEND(;TZID=[^:]*)?:/ {
if (inevent) {
# print $0
date2 = strftime("%Y-%m-%d %a", datetimestamp($2));
time2 = strftime("%H:%M", datetimestamp($2));
}
}
# TODO items may (should?) have a DUE date/time.
/^DUE(;TZID=[^:]*)?:/ {
if (intodo){
date2 = strftime("%Y-%m-%d %a", datetimestamp($2));
time2 = strftime("%H:%M", datetimestamp($2));
}
}
# deadline with only a date
/^DUE;VALUE=DATE/ {
# print "DUE;VALUE=DATE entry:" $0
# print "... date part is >" $2 "<"
# print "... date2 before " date2
if (intodo) {
#date2 = gensub("([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9]).*[\r]*", "\\1-\\2-\\3", "g", $2)
date2 = datestamp($2);
time2 = ""
}
# print "... date2 after " date2
}
# The description will the contents of the entry in org-mode.
# this line may be continued.
/^DESCRIPTION/ {
$1 = "";
entry = entry "\n" gensub("\r", "", "g", $0);
indescription = 1;
}
/^LOCATION/ {
$1 = "";
location = gensub("\r", "", "g", $0);
}
# the status of a TODO item: we know about NEEDS-ACTION and
# COMPLETED. There may be others...
/^STATUS/ {
if ($2 == "NEEDS-ACTION")
todotype = "TODO";
else if ($2 == "COMPLETED")
todotype = "DONE";
else
todotype = "UNKNOWN";
}
# is there a repetition rule. I don't know how general this is but
# Microsoft's Outlook calendar uses this for repeats
/^RRULE/ {
# print ">>> Checking rule with string: " $2;
i = match($2,"FREQ=[A-Z]+;");
# printf(">>> Index=%d start=%d length=%d\n\n", i, RSTART, RLENGTH);
frequency = substr($2, RSTART+5, RLENGTH-6);
# print ">>> Frequency is " frequency "\n\n";
i = match($2,"INTERVAL=[0-9]+;");
interval = 1; # default interval if none is found
if (i>0) {
interval = substr($2, RSTART+9, RLENGTH-10);
}
period = "";
if (frequency == "DAILY") {
period = "d";
}
else if (frequency == "WEEKLY") {
period = "w";
}
else if(frequency == "MONTHLY") {
period = "m";
}
else if(frequency == "YEARLY") {
period = "y";
}
if (period != "") {
repeat = sprintf(" +%d%s", interval, period);
}
# print ">>> Repeat is " repeat;
}
# the summary will be the org heading
/^SUMMARY/ {
$1 = "";
if (!havesummary) {
summary = gensub("\r", "", "g", $0);
insummary = 1;
}
}
# the unique ID will be stored as a property of the entry
/^UID/ {
$1 = "";
id = gensub("\r", "", "g", $0);
inuid = 1;
}
# when we reach the end of the event line, we output everything we
# have collected so far, creating a top level org headline with the
# date/time stamp, unique ID property and the contents, if any
/^END:VEVENT/ {
# translate \n sequences to actual newlines and unprotect commas (,)
print "* " gensub("\\\\,", ",", "g", gensub("\\\\n", " ", "g", summary)) " :" NAME ":"
print ":PROPERTIES:"
print ":ID: " id
if (location != "") {
print ":LOCATION: " gensub("\\\\,", ",", "g", location);
}
print ":END:"
if (date1 == date2) {
if (time2 == "")
print " <" date1 time1 repeat ">"
else
print " <" date1 time1 "-" time2 repeat ">"
}
else {
if (time1 == "")
print "<" date1 ">--<" date2 ">"
else
print " <" date1 time1 ">--<" date2 " " time2 ">"
}
# for the entry, convert all embedded "\n" strings to actual newlines
print ""
# translate \n sequences to actual newlines and unprotect commas (,)
print gensub("\\\\,", ",", "g", gensub("\\\\n", "\n", "g", entry));
print "** COMMENT original iCal entry"
print gensub("\r", "", "g", icalentry)
summary = ""
date = ""
date1 = ""
date2 = ""
time1 = ""
time2 = ""
entry = ""
icalentry = ""
indescription = 0
inevent = 0
insummary = 0
period = "";
repeat = "";
}
# the end of a TODO item is similar to an event except that the dates
# are used for scheduling and deadline information
/^END:VTODO/ {
# translate \n sequences to actual newlines and unprotect commas (,)
print "* " todotype " " gensub("\\\\,", ",", "g", gensub("\\\\n", " ", "g", summary)) " :" NAME ":"
# scheduling and deadline information come immediately after the
# headline, before properties
if (date1 != "") {
if (date2 != "")
if (time2 != "")
print "SCHEDULED: <" date1 time1 "> DEADLINE: <" date2 " " time2 "> "
else
print "SCHEDULED: <" date1 time1 "> DEADLINE: <" date2 "> "
else
print "SCHEDULED: <" date1 time1 "> "
} else if (date2 != "") {
if (time2 != "")
print "DEADLINE: <" date2 " " time2 "> "
else
print "DEADLINE: <" date2 "> "
}
# now come the properties which include the ID always and possibly
# a location
print ":PROPERTIES:"
print ":ID: " id
if (location != "") {
print ":LOCATION: " gensub("\\\\,", ",", "g", location);
}
print ":END:"
# now the entry; we put in a blank line just because that's the
# way I like it, ah ha ah ha... ;-)
print ""
# translate \n sequences to actual newlines and unprotect commas (,)
print gensub("\\\\,", ",", "g", gensub("\\\\n", "\n", "g", entry));
print "** COMMENT original iCal entry"
print gensub("\r", "", "g", icalentry)
summary = "";
date = "";
date1 = "";
date2 = "";
time1 = "";
time2 = "";
entry = "";
icalentry = "";
indescription = 0;
inevent = 0;
insummary = 0;
intodo = 0;
period = "";
repeat = "";
}
# Local Variables:
# time-stamp-line-limit: 1000
# time-stamp-format: "%04y.%02m.%02d %02H:%02M:%02S"
# time-stamp-active: t
# time-stamp-start: "Last change:[ \t]+"
# time-stamp-end: "$"
# End:

View File

@ -1,6 +1,6 @@
(define-package "dash" "20240103.1301" "A modern list library for Emacs" (define-package "dash" "20230714.723" "A modern list library for Emacs"
'((emacs "24")) '((emacs "24"))
:commit "e32a70ca636bad42232b6c79f1491dc86802a721" :authors :commit "f46268c75cb7c18361d3cee942cd4dc14a03aef4" :authors
'(("Magnar Sveen" . "magnars@gmail.com")) '(("Magnar Sveen" . "magnars@gmail.com"))
:maintainers :maintainers
'(("Magnar Sveen" . "magnars@gmail.com")) '(("Magnar Sveen" . "magnars@gmail.com"))

View File

@ -1,6 +1,6 @@
;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- ;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*-
;; Copyright (C) 2012-2024 Free Software Foundation, Inc. ;; Copyright (C) 2012-2023 Free Software Foundation, Inc.
;; Author: Magnar Sveen <magnars@gmail.com> ;; Author: Magnar Sveen <magnars@gmail.com>
;; Version: 2.19.1 ;; Version: 2.19.1

View File

@ -2,7 +2,7 @@ This is dash.info, produced by makeinfo version 6.7 from dash.texi.
This manual is for Dash version 2.19.1. This manual is for Dash version 2.19.1.
Copyright © 20122024 Free Software Foundation, Inc. Copyright © 20122023 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,
@ -24,7 +24,7 @@ Dash
This manual is for Dash version 2.19.1. This manual is for Dash version 2.19.1.
Copyright © 20122024 Free Software Foundation, Inc. Copyright © 20122023 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,

171
init.el
View File

@ -472,20 +472,6 @@
mc/mark-previous-like-this mc/mark-previous-like-this
mc/mark-all-like-this)) mc/mark-all-like-this))
(use-package olivetti
:ensure t
:commands (olivetti-mode)
:preface (progn
(defun turn-on-olivetti-mode ()
"Turn on `olivetti-mode'."
(interactive)
(olivetti-mode 1))
(defun turn-off-olivetti-mode ()
"Turn off `olivetti-mode'."
(interactive)
(olivetti-mode -1)))
:init (setq-default olivetti-body-width 0.618034))
(use-package undo-tree (use-package undo-tree
:ensure t :ensure t
:commands (global-undo-tree-mode :commands (global-undo-tree-mode
@ -538,8 +524,6 @@
db/org-timestamp-difference db/org-timestamp-difference
db/org-capture-code-snippet db/org-capture-code-snippet
hydra-org-clock/body hydra-org-clock/body
hydra-org-jump/body
hydra-org-custom/body
db/make-org-capture-frame db/make-org-capture-frame
db/org-onenote-open db/org-onenote-open
db/org-outlook-open db/org-outlook-open
@ -623,10 +607,10 @@
;; Keywords and Tags ;; Keywords and Tags
(setq org-todo-keywords (setq org-todo-keywords
'((sequence "TODO(t@)" "CONT(n!)" "REFINE(f!)" "|" "DONE(d@)" "CANC(c@)" "MRGD(m@)") '((sequence "TODO(t)" "CONT(n!)" "REFINE(f!)" "|" "DONE(d@/!)" "CANC(c@/!)" "MRGD(m@/!)")
(sequence "GOTO(g@)" "ATTN(a!)" "|" "DONE(d@)") (sequence "GOTO(g)" "ATTN(a!)" "|" "DONE(d@/!)")
(sequence "READ(r@)" "CONT(n!)" "|" "DONE(d@)") (sequence "READ(r)" "CONT(n!)" "|" "DONE(d@/!)")
(sequence "DELG(e@)" "WAIT(w@)" "HOLD(h@)" "|" "CANC(c@)")) (sequence "DELG(e@/!)" "WAIT(w@/!)" "HOLD(h@/!)" "|" "CANC(c@/!)"))
org-todo-state-tags-triggers org-todo-state-tags-triggers
'(("WAIT" ("HOLD") ("WAIT" . t)) '(("WAIT" ("HOLD") ("WAIT" . t))
@ -989,13 +973,10 @@
((org-agenda-overriding-header "Deadlines") ((org-agenda-overriding-header "Deadlines")
(org-agenda-sorting-strategy '(deadline-up priority-down)) (org-agenda-sorting-strategy '(deadline-up priority-down))
(org-deadline-warning-days 30))) (org-deadline-warning-days 30)))
(tags-todo "TODO={CONT\\|ATTN}-HOLD" (tags-todo "TODO={CONT\\|ATTN}-HOLD-TIMESTAMP>=\"<today>\"-SCHEDULED<>\"\"-NOT_BEFORE>=\"<today>\""
((org-agenda-overriding-header "Things to do next (Task shortlist and WIP, TODO ∈ {CONT,ATTN}, not scheduled)") ((org-agenda-overriding-header "Things to do next (Task shortlist and WIP, TODO ∈ {CONT,ATTN}, not scheduled)")))
(org-agenda-todo-ignore-scheduled 'all) (tags-todo "TODO<>\"CONT\"-HOLD-SOMEWHEN-DATE-WAIT-TEMPLATE-SCHEDULED<>\"\"-NOT_BEFORE>=\"<today>\""
(org-agenda-todo-ignore-timestamp 0)))
(tags-todo "TODO<>\"CONT\"-HOLD-SOMEWHEN-DATE-WAIT-TEMPLATE"
((org-agenda-overriding-header "Task Backlog (not WIP, not scheduled)") ((org-agenda-overriding-header "Task Backlog (not WIP, not scheduled)")
(org-agenda-todo-ignore-scheduled 'all)
(org-tags-match-list-sublevels t))))) (org-tags-match-list-sublevels t)))))
("B" "Backlog" ("B" "Backlog"
@ -1014,20 +995,44 @@
;; DEADLINE is not necessary, as items will appear on the ;; DEADLINE is not necessary, as items will appear on the
;; deadline view anyway. ;; deadline view anyway.
;; Check whether any NOT_BEFORE entries are not actually timestaps
(org-ql-block '(and (property "NOT_BEFORE")
(not (string-match-p org-element--timestamp-regexp
(property "NOT_BEFORE"))))
((org-ql-block-header "Items whose NOT_BEFORE entry is not a timestamp")))
;; Check whether any NOT_BEFORE is behind a SCHEDULED
(org-ql-block '(and (property "NOT_BEFORE")
(scheduled)
(> (org-2ft (property "NOT_BEFORE"))
(org-2ft (property "SCHEDULED"))))
((org-ql-block-header "Items whose NOT_BEFORE value is after SCHEDULED")))
;; Check whether any NOT_BEFORE is beind their DEADLINE
(org-ql-block '(and (property "NOT_BEFORE")
(deadline)
(> (org-2ft (property "NOT_BEFORE"))
(org-2ft (property "DEADLINE"))))
((org-ql-block-header "Items whose NOT_BEFORE value is after their DEADLINE")))
)) ))
("U" "Unsupervised (Waiting, Missed Appointments, Hold)" ("U" "Unsupervised (Waiting, Missed Appointments, Hold)"
((tags "WAIT-TODO={DONE\\|CANC\\|MRGD}-HOLD-SOMEWHEN-SCHEDULED>=\"<today>\"" ((tags "WAIT-TODO={DONE\\|CANC\\|MRGD}-HOLD-SOMEWHEN-SCHEDULED>=\"<today>\"-NOT_BEFORE>=\"<today>\""
((org-agenda-overriding-header "Waiting For List"))) ((org-agenda-overriding-header "Waiting For List")))
(tags-todo "DATE-TIMESTAMP>=\"<today>\"" (tags-todo "DATE-TIMESTAMP>=\"<today>\""
((org-agenda-overriding-header "Missed appointments (DATEs with timestamp in the past)"))) ((org-agenda-overriding-header "Missed appointments (DATEs with timestamp in the past)")))
(tags "HOLD-TODO={DONE\\|CANC\\|MRGD}-SOMEWHEN-SCHEDULED>=\"<today>\"" (tags "REFILE"
((org-agenda-files (list db/org-default-refile-file))
(org-agenda-overriding-header "Things to refile (make it empty!)")))
(tags "HOLD-TODO={DONE\\|CANC\\|MRGD}-SOMEWHEN-SCHEDULED>=\"<today>\"-NOT_BEFORE>=\"<today>\""
((org-agenda-overriding-header "Tasks on Hold"))))) ((org-agenda-overriding-header "Tasks on Hold")))))
("S" "Somewhen (Do if nothing else to do, i.e., personal backlog)" ("S" "Somewhen (Do if nothing else to do, i.e., personal backlog)"
((tags "TAGS={SOMEWHEN}+TODO=\"\"-NOP-TOPIC-PERIODIC-DATE-SCHEDULED>=\"<today>\"" ((tags "TAGS={SOMEWHEN}+TODO=\"\"-TAGS={NOP\\|TOPIC}-PERIODIC-DATE-SCHEDULED>=\"<today>\"-NOT_BEFORE>=\"<today>\""
((org-agenda-overriding-header "Open Tasks to do SOMEWHEN (no TODO keyword, no PERIODIC, no DATE, no now or future SCHEDULED)"))) ((org-agenda-overriding-header "Open Tasks to do SOMEWHEN (no TODO keyword, no PERIODIC, no DATE, no now or future SCHEDULED)")))
(tags-todo "SOMEWHEN-HOLD" (tags-todo "SOMEWHEN-NOT_BEFORE>=\"<today>\"-ALLTAGS={HOLD}"
((org-agenda-overriding-header "Things To Do SOMEWHEN") ((org-agenda-overriding-header "Things To Do SOMEWHEN")
(org-agenda-todo-ignore-with-date t) (org-agenda-todo-ignore-with-date t)
(org-tags-match-list-sublevels nil))))) (org-tags-match-list-sublevels nil)))))
@ -1035,11 +1040,11 @@
("P" "Current Projects and Topics" ("P" "Current Projects and Topics"
((stuck "" ((stuck ""
((org-agenda-overriding-header "Stuck Complex Tasks"))) ((org-agenda-overriding-header "Stuck Complex Tasks")))
(tags "TAGS={NOTE}-TODO={CANC\\|DONE\\|MRGD}-HOLD-NOP-SOMEWHEN-SCHEDULED>=\"<today>\"" (tags "TAGS={NOTE}-TODO={CANC\\|DONE\\|MRGD}-HOLD-NOP-SOMEWHEN-SCHEDULED>=\"<today>\"-NOT_BEFORE>=\"<today>\""
((org-agenda-overriding-header "Project Notes (items explicitly tagged with NOTE but not NOP)"))) ((org-agenda-overriding-header "Project Notes (items explicitly tagged with NOTE but not NOP)")))
(tags "TAGS={TOPIC}-TODO={DONE\\|CANC\\|MRGD}-SOMEWHEN-SCHEDULED>=\"<today>\"-HOLD-WAIT" (tags "TAGS={TOPIC}-TODO={DONE\\|CANC\\|MRGD}-SOMEWHEN-SCHEDULED>=\"<today>\"-HOLD-WAIT-NOT_BEFORE>=\"<today>\""
((org-agenda-overriding-header "Topics (items directly tagged with TOPIC)"))) ((org-agenda-overriding-header "Topics (items directly tagged with TOPIC)")))
(tags "TAGS={PERIODIC}-TODO={DONE\\|CANC\\|MRGD}-HOLD-SCHEDULED>=\"<today>\"-HOLD-WAIT" (tags "TAGS={PERIODIC}-TODO={DONE\\|CANC\\|MRGD}-HOLD-SCHEDULED>=\"<today>\"-HOLD-WAIT-NOT_BEFORE>=\"<today>\""
((org-agenda-overriding-header "Periodic Projects (PERIODIC, not scheduled in the future, not done, not on hold)"))))) ((org-agenda-overriding-header "Periodic Projects (PERIODIC, not scheduled in the future, not done, not on hold)")))))
("W" "Weekly Review" ("W" "Weekly Review"
@ -1090,22 +1095,17 @@
(file db/org-default-refile-file) (file db/org-default-refile-file)
,(concat "* TODO [#B] %^{What}\n" ,(concat "* TODO [#B] %^{What}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n" ":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\nVia %a.\n\n" "%a\n"
"%?") "%?")
:empty-lines 1) :empty-lines 1)
("g" "Record new goal" ("g" "Record new goal with first item"
entry entry
(file db/org-default-refile-file) (file db/org-default-refile-file)
,(concat "* %^{Description} (%^{Ticket Number}) :GOAL:\n" ,(concat "* %^{Ticket Description} (%^{Ticket Number}) :GOAL:\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n** TODO [#B] %^{First Task}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n" ":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n%?")) "\n%?"))
("h" "Headline (generic Org item)"
entry
(file db/org-default-refile-file)
,(concat "* [#B] %^{What}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"%a\n"
"%?"))
("n" "Note" ("n" "Note"
entry entry
(file db/org-default-refile-file) (file db/org-default-refile-file)
@ -1243,9 +1243,7 @@
:bind (:map org-tree-slide-mode-map :bind (:map org-tree-slide-mode-map
("<C-down>" . org-tree-slide-display-header-toggle) ("<C-down>" . org-tree-slide-display-header-toggle)
("<C-right>" . org-tree-slide-move-next-tree) ("<C-right>" . org-tree-slide-move-next-tree)
("<C-left>" . org-tree-slide-move-previous-tree)) ("<C-left>" . org-tree-slide-move-previous-tree)))
:hook ((org-tree-slide-play . turn-on-olivetti-mode)
(org-tree-slide-stop . turn-off-olivetti-mode)))
(use-package org-roam (use-package org-roam
:init (progn :init (progn
@ -2090,14 +2088,7 @@ Note that this workaround is incomplete, as explained in this comment."
(setq suggest-key-bindings t (setq suggest-key-bindings t
extended-command-suggest-shorter t extended-command-suggest-shorter t
completions-detailed t completions-detailed t
completion-cycle-threshold 10 completion-cycle-threshold 10)
completion-styles '(orderless basic)
completion-category-defaults nil
;; Via https://protesilaos.com/emacs/dotemacs, with additional changes
completion-category-overrides '((file (styles . (basic partial-completion orderless)))
(bookmark (styles . (basic substring orderless)))
(imenu (styles . (basic substring orderless)))
(kill-ring (styles . (emacs22 orderless)))))
(use-package helm (use-package helm
:ensure t :ensure t
@ -2105,8 +2096,7 @@ Note that this workaround is incomplete, as explained in this comment."
:autoload (helm-execute-persistent-action :autoload (helm-execute-persistent-action
helm-select-action helm-select-action
helm-make-source) helm-make-source)
:commands (helm-show-kill-ring) :defines (helm-source-bookmarks) ; via helm-bookmarks.el
:defines (helm-source-bookmarks) ; via helm-bookmarks.el
:init (setq helm-command-prefix-key "C-c h" ; see `db/run-init' for explicit binding :init (setq helm-command-prefix-key "C-c h" ; see `db/run-init' for explicit binding
helm-input-idle-delay 0.0 helm-input-idle-delay 0.0
helm-buffers-fuzzy-matching t helm-buffers-fuzzy-matching t
@ -2146,8 +2136,13 @@ Note that this workaround is incomplete, as explained in this comment."
(bind-key "C-i" #'helm-execute-persistent-action helm-map) (bind-key "C-i" #'helm-execute-persistent-action helm-map)
(bind-key "C-z" #'helm-select-action helm-map))) (bind-key "C-z" #'helm-select-action helm-map)))
(use-package helm-ring
:commands (helm-show-kill-ring))
(use-package ivy (use-package ivy
:commands (ivy-mode) :ensure t
:commands (ivy-mode
ivy-resume)
:diminish ivy-mode :diminish ivy-mode
:init (setq ivy-use-virtual-buffers t :init (setq ivy-use-virtual-buffers t
ivy-magic-tilde nil ivy-magic-tilde nil
@ -2168,6 +2163,22 @@ Note that this workaround is incomplete, as explained in this comment."
;; functionality. ;; functionality.
(define-key ivy-minibuffer-map (kbd "S-SPC") nil))) (define-key ivy-minibuffer-map (kbd "S-SPC") nil)))
(use-package counsel
:ensure t
:commands (counsel-org-goto-all
counsel-M-x
counsel-find-file
counsel-info-lookup-symbol
counsel-unicode-char
counsel-descbinds
counsel-describe-variable
counsel-describe-function
counsel-recentf
counsel-shell-history))
(use-package smex
:init (setq smex-save-file (expand-file-name "smex-items" emacs-d-userdata)))
(use-package swiper (use-package swiper
:ensure t :ensure t
:commands (swiper :commands (swiper
@ -2183,22 +2194,6 @@ Note that this workaround is incomplete, as explained in this comment."
:commands (company-mode global-company-mode) :commands (company-mode global-company-mode)
:init (setq company-show-quick-access t)) :init (setq company-show-quick-access t))
(use-package marginalia
:ensure t
:commands (marginalia-mode)
:init (setq marginalia-max-relative-age 0))
(use-package vertico
:ensure t
:commands (vertico-mode))
(use-package orderless
:ensure t
:init (setq orderless-match-faces ; Some of the default faces are hard to
; read with when solarized is enabled;
; only keep those that are readable
[orderless-match-face-1 orderless-match-face-2]))
;; * Navigation ;; * Navigation
@ -2297,8 +2292,7 @@ eventuelly be set to nil, however)."
(use-package isearch (use-package isearch
:init (setq isearch-allow-scroll t :init (setq isearch-allow-scroll t
isearch-lazy-count t isearch-lazy-count t
isearch-lax-whitespace nil search-whitespace-regexp "[ \t\r\n]+"))
isearch-regexp-lax-whitespace nil))
(use-package goto-last-change (use-package goto-last-change
:commands goto-last-change) :commands goto-last-change)
@ -2494,6 +2488,8 @@ eventuelly be set to nil, however)."
(use-package shell (use-package shell
:commands (shell) :commands (shell)
:bind (:map shell-mode-map
("C-r" . counsel-shell-history))
:config (progn :config (progn
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
(add-hook 'comint-output-filter-functions 'comint-strip-ctrl-m) (add-hook 'comint-output-filter-functions 'comint-strip-ctrl-m)
@ -2941,16 +2937,13 @@ eventuelly be set to nil, however)."
minibuffer-depth-indicate-mode minibuffer-depth-indicate-mode
ace-window-display-mode ace-window-display-mode
key-chord-mode key-chord-mode
;; ivy-mode ivy-mode
minions-mode minions-mode
which-key-mode which-key-mode
projectile-mode projectile-mode
yas-global-mode yas-global-mode
global-git-commit-mode global-git-commit-mode
;; global-company-mode global-company-mode))
marginalia-mode
vertico-mode
))
(with-demoted-errors "Cannot activate mode: %s" (with-demoted-errors "Cannot activate mode: %s"
(funcall mode +1))) (funcall mode +1)))
@ -2964,6 +2957,10 @@ eventuelly be set to nil, however)."
(with-demoted-errors "Cannot activate `vlf': %s" (with-demoted-errors "Cannot activate `vlf': %s"
(require 'vlf-setup)) (require 'vlf-setup))
;; Explicitly require helm, because autoloading is difficult with helm's
;; separate `helm-command-prefix-key' mechanism.
(require 'helm)
;; Global Hooks ;; Global Hooks
(add-hook 'minibuffer-setup-hook 'cursor-intangible-mode) (add-hook 'minibuffer-setup-hook 'cursor-intangible-mode)
@ -3004,6 +3001,7 @@ eventuelly be set to nil, however)."
(bind-key "C-S-c C-S-c" #'mc/edit-lines) (bind-key "C-S-c C-S-c" #'mc/edit-lines)
(bind-key "C-Z" #'undo-tree-redo) (bind-key "C-Z" #'undo-tree-redo)
(bind-key "C-c C-<" #'mc/mark-all-like-this) (bind-key "C-c C-<" #'mc/mark-all-like-this)
(bind-key "C-c C-r" #'ivy-resume)
(bind-key "C-c D" #'define-word) (bind-key "C-c D" #'define-word)
(bind-key "C-c J" #'avy-goto-word-or-subword-1) (bind-key "C-c J" #'avy-goto-word-or-subword-1)
(bind-key "C-c a" #'org-agenda) (bind-key "C-c a" #'org-agenda)
@ -3017,7 +3015,7 @@ eventuelly be set to nil, however)."
(bind-key "C-c n f" #'org-roam-node-find) (bind-key "C-c n f" #'org-roam-node-find)
(bind-key "C-c n i" #'org-roam-node-insert) (bind-key "C-c n i" #'org-roam-node-insert)
(bind-key "C-c n c" #'org-roam-capture) (bind-key "C-c n c" #'org-roam-capture)
(bind-key "C-c o" #'hydra-org-custom/body) (bind-key "C-c o" #'hydra-org-clock/body)
(bind-key "C-c t" #'hydra-toggle/body) (bind-key "C-c t" #'hydra-toggle/body)
(bind-key "C-h C-f" #'find-function) (bind-key "C-h C-f" #'find-function)
(bind-key "C-h C-k" #'find-function-on-key) (bind-key "C-h C-k" #'find-function-on-key)
@ -3050,10 +3048,15 @@ eventuelly be set to nil, however)."
;; Overwrite certain keybindings only if packages are avilable ;; Overwrite certain keybindings only if packages are avilable
(when (package-installed-p 'counsel)
(bind-key "M-x" #'counsel-M-x) ; gets nicer sorting with smex installed
(bind-key "C-x C-f" #'counsel-find-file)
(bind-key "C-h f" #'counsel-describe-function)
(bind-key "C-h v" #'counsel-describe-variable)
(bind-key "C-h b" #'counsel-descbinds)
(bind-key "C-S-s" #'counsel-grep-or-swiper))
(when (package-installed-p 'helm) (when (package-installed-p 'helm)
;; Explicitly require helm, because autoloading is difficult with helm's
;; separate `helm-command-prefix-key' mechanism.
(require 'helm)
(bind-key "M-y" #'helm-show-kill-ring) (bind-key "M-y" #'helm-show-kill-ring)
(bind-key helm-command-prefix-key #'helm-command-prefix)) (bind-key helm-command-prefix-key #'helm-command-prefix))

View File

@ -146,8 +146,8 @@ in the main agenda view."
("EShell" ?e db/run-or-hide-eshell) ("EShell" ?e db/run-or-hide-eshell)
("Refile File" ?r #'(lambda () (interactive) (find-file db/org-default-refile-file))) ("Refile File" ?r #'(lambda () (interactive) (find-file db/org-default-refile-file)))
("Goto Currnet Clock" ?c db/org-clock-goto-first-open-checkbox) ("Goto Currnet Clock" ?c db/org-clock-goto-first-open-checkbox)
("Info Lookup" ?I info-lookup-symbol) ("Info Lookup" ?I counsel-info-lookup-symbol)
("Unicode Lookup" ?U insert-char) ("Unicode Lookup" ?U counsel-unicode-char)
("Timeline of Day" ?T timeline-tools-format-timeline-of-day) ("Timeline of Day" ?T timeline-tools-format-timeline-of-day)
("Copy template to point" ?C db/org-insert-checklist)) ("Copy template to point" ?C db/org-insert-checklist))
"Mapping of frequently used features to functions implementing "Mapping of frequently used features to functions implementing

View File

@ -21,18 +21,17 @@
;; zooming with single keystrokes (from oremacs) ;; zooming with single keystrokes (from oremacs)
(defhydra hydra-zoom (:color red (defhydra hydra-zoom (:color red
:body-pre (require 'face-remap)) :body-pre (require 'face-remap))
;; the following newline is important, as otherwise the format string is not ;; the following newline is important, as otherwise the format string is not
;; interpreted correctly; cf. https://oremacs.com/2015/02/23/hydra-0.11.0/ ;; interpreted correctly; cf. https://oremacs.com/2015/02/23/hydra-0.11.0/
" "
Zoom (%`text-scale-mode-amount): " Zoom (%`text-scale-mode-amount): "
("g" text-scale-increase "increase") ("g" text-scale-increase "increase")
("l" text-scale-decrease "decrease") ("l" text-scale-decrease "decrease"))
("0" (text-scale-adjust 0) "reset"))
(defhydra hydra-rectangle (:body-pre (rectangle-mark-mode 1) (defhydra hydra-rectangle (:body-pre (rectangle-mark-mode 1)
:color pink :color pink
:post (deactivate-mark)) :post (deactivate-mark))
" "
^_k_^ _d_elete _s_tring ^_k_^ _d_elete _s_tring
_h_ _l_ _o_k _y_ank _h_ _l_ _o_k _y_ank
@ -49,7 +48,7 @@ _h_ _l_ _o_k _y_ank
("r" (if (region-active-p) ("r" (if (region-active-p)
(deactivate-mark) (deactivate-mark)
(rectangle-mark-mode 1)) (rectangle-mark-mode 1))
nil) nil)
("y" yank-rectangle nil) ("y" yank-rectangle nil)
("u" undo nil) ("u" undo nil)
("s" string-rectangle nil) ("s" string-rectangle nil)

View File

@ -19,6 +19,7 @@
(require 'ox-icalendar) (require 'ox-icalendar)
(require 'org-ql) (require 'org-ql)
(autoload 'counsel-org-goto-all "counsel")
(autoload 'which-function "which-func") (autoload 'which-function "which-func")
(autoload 'org-element-property "org-element") (autoload 'org-element-property "org-element")
@ -209,8 +210,6 @@ _y_: ?y? year _q_: quit _L__l__c_: ?l?
The remaining effort is computed as the planned effort minus the The remaining effort is computed as the planned effort minus the
already clocked time. If this result is negative, return zero. already clocked time. If this result is negative, return zero.
The clocked time is computed over the complete subtree of the Org
item at point, and not only from the item itself.
Return the remaining effort as duration string by default. When Return the remaining effort as duration string by default. When
optional AS-NUMBER is non-nil, return the effort as number. optional AS-NUMBER is non-nil, return the effort as number.
@ -479,11 +478,10 @@ user for the next task to clock into."
(message org-clock-current-task)) (message org-clock-current-task))
(defun db/org-clocked-time-for-current-item () (defun db/org-clocked-time-for-current-item ()
"Return overall clocked time for the subtree of the Org item at point. "Return all clocked time for Org item at point.
The clocked time of the item itself is also included, as is the Also includes the currently running clock when the current item
time of the currently running clock, in case item at point is is clocked in."
clocked in."
(unless (derived-mode-p 'org-mode) (unless (derived-mode-p 'org-mode)
(user-error "Not in Org mode buffer, aborting")) (user-error "Not in Org mode buffer, aborting"))
@ -853,14 +851,19 @@ default task, though."
Current Task: %s(replace-regexp-in-string \"%\" \"%%\" (or org-clock-current-task \"\")); Current Task: %s(replace-regexp-in-string \"%\" \"%%\" (or org-clock-current-task \"\"));
- Clock in to [_w_]ork, [_h_]ome, [_b_]reak default task - Clock in to [_w_]ork, [_h_]ome, [_b_]reak default task
- Clock in to [_l_]ast, or [_s_]elect task to clock in to - Clock in to [_l_]ast, or [_s_]elect task to clock in to
- [_j_]ump to current clock - [_j_]ump to current clock or to [_a_]ny item
- Clock [_o_]ut - Clock [_o_]ut
" "
("w" (db/org-clock-in-work-task) nil) ("w" (db/org-clock-in-work-task) nil)
("h" (db/org-clock-in-home-task) nil) ("h" (db/org-clock-in-home-task) nil)
("b" (db/org-clock-in-break-task) nil) ("b" (db/org-clock-in-break-task) nil)
("s" (org-clock-in '(4)) nil) ("s" (lambda ()
("j" (db/org-clock-goto-first-open-checkbox) nil) (interactive)
(org-clock-in '(4)))
nil)
("j" (db/org-clock-goto-first-open-checkbox)
nil)
("a" counsel-org-goto-all nil)
("o" org-clock-out nil) ("o" org-clock-out nil)
("l" db/org-clock-in-last-task nil)) ("l" db/org-clock-in-last-task nil))
@ -1034,36 +1037,6 @@ The password is assumed to be stored at the PASSWORD property."
heading heading
org-password-manager-default-password-wait-time)))) org-password-manager-default-password-wait-time))))
(defhydra hydra-org-jump (:color blue)
;; Quote %, as otherwise they would be misinterpreted as format characters
"
Current Task: %s(replace-regexp-in-string \"%\" \"%%\" (or org-clock-current-task \"\"));
- Jump to [_c_]urrent clock
- Jump to [_a_]ny item
- Jump to item [_s_]elected from clock history
"
("c" (db/org-clock-goto-first-open-checkbox nil)
nil)
("a" (org-refile '(4)) nil)
("s" (db/org-clock-goto-first-open-checkbox t)
nil))
(defhydra hydra-org-custom (:foreign-keys warn
:exit t)
"
Custom Org commands:
_c_ Clocking commands
_j_ Jumping commands
_l_ Linking commands
_a_ Open agenda
_q_ Quit this hydra"
("c" hydra-org-clock/body nil)
("j" hydra-org-jump/body nil)
("l" hydra-org-linking/body nil)
("a" db/org-agenda nil)
("q" (message "Abort") nil)
("C-g" (message "Abort") nil))
;;; Checklist Handling ;;; Checklist Handling

View File

@ -36,9 +36,8 @@
;;; Application Shortcuts ;;; Application Shortcuts
(defun db/run-or-hide-ansi-term () (defun db/run-or-hide-ansi-term ()
"Find *ansi-term* buffer or run `ansi-term' with `explicit-shell-file-name'. "Find `*ansi-term*' or run `ansi-term' with `explicit-shell-file-name'.
If already in `*ansi-term*' buffer, bury it."
If already in *ansi-term* buffer, bury it."
(interactive) (interactive)
(if (string= "term-mode" major-mode) (if (string= "term-mode" major-mode)
(bury-buffer) (bury-buffer)
@ -537,17 +536,14 @@ entries, even if I want to use the input directly."
(car grep-files-history) (car grep-files-history)
(car (car grep-files-aliases)))) (car (car grep-files-aliases))))
(files (completing-read (files (completing-read
(format "Search for \"%s\" in files matching wildcard (default: %s): " (format "Search for \"%s\" in files matching wildcard: "
regexp regexp)
default) nil nil nil
(delete-dups (delete-dups
(delq nil (delq nil
(append (list default default-alias default-extension) (append (list default default-alias default-extension)
grep-files-history
(mapcar #'car grep-files-aliases)))) (mapcar #'car grep-files-aliases))))
nil nil nil 'grep-files-history)))
'grep-files-history
default)))
(and files (and files
(or (cdr (assoc files grep-files-aliases)) (or (cdr (assoc files grep-files-aliases))
files)))) files))))