Compare commits

...

7 Commits

7 changed files with 33 additions and 29 deletions

8
README
View File

@@ -47,12 +47,12 @@ The attributes section follows the text section. The attributes section ends
with a single newline. Text including and following a hash in the attributes
section will be ignoroed.
The command section follows the attributes section. The command section is
The content section follows the attributes section. The content section is
run as a single argument following the invocation `$ sh -c`, like the C
standard library's system(3). Each line in the command section is preceded by
a horizontal tab, which is removed from the argument; if a line in the command
standard library's system(3). Each line in the content section is preceded by
a horizontal tab, which is removed from the argument; if a line in the content
section is not preceded by a tab, the omission is considered a syntax error (a
"naked line") and menu(1) exits unsuccessfully. The command section ends with
"naked line") and menu(1) exits unsuccessfully. The content section ends with
two consecutive newlines.
## POSIX systems

View File

@@ -1,7 +1,7 @@
#!usr/bin/env menu
$ echo Hello, world.
# ^^^ Text VVV Command
# ^^^ Text VVV Content
echo Hello, world.
$ cat Makefile

View File

@@ -4,13 +4,14 @@ import re, sys, xml.etree.ElementTree as ET
ET.register_namespace("", "http://www.w3.org/2005/Atom")
ET.register_namespace("media", "http://search.yahoo.com/mrss/")
ET.register_namespace("yt", "http://www.youtube.com/xml/schemas/2015")
def sortby(entry):
return entry.findall("{http://www.w3.org/2005/Atom}published")[0].text
macrofeed = ET.Element('feed')
macrofeed.extend(
sorted([
entry
# Split the input by file.
# Split the input by file. This relies on a typical <XML /> tag
# starting a file. Theoretically this assumption could be wrong,
# but in that case the XML parser would break before
# ytfeed.aggregate could spit malformed output.
for feed in re.split(r'<\?xml.*?\?>', sys.stdin.read())[1:]
# Get the entries out of each file.
for entry
@@ -18,9 +19,8 @@ macrofeed.extend(
.findall("{http://www.w3.org/2005/Atom}entry")
],
# Gets the publication date and sorts the entries from old to new.
key = lambda entry
key = lambda entry # (this is a text sort but it still works)
: entry.findall("{http://www.w3.org/2005/Atom}published")[0].text,
reverse = False # toggle this to switch the order
)
)
print(ET.tostring(macrofeed, encoding="unicode"))

View File

@@ -20,7 +20,7 @@ for entry in root.findall("{http://www.w3.org/2005/Atom}entry"):
+ f("%-22s - ", entry, "author/name")
+ f("%s", entry, "title") + "\n\n"
# Command
+ "\t" + "ytfeed.browse-entry <<EOF | ../menu" + "\n"
+ "\t" + "ytfeed.browse-entry <<EOF | menu" + "\n"
+ "\t" + ET.tostring(entry, encoding="unicode")
.replace("\n", "\n\t").rstrip() + "\n"
+ "\tEOF",

View File

@@ -9,8 +9,11 @@ directory = sys.argv[1]
for f in os.listdir(directory):
file_name = os.path.join(directory, f)
if os.path.isfile(file_name) and f[-4:] == ".xml":
tree = ET.parse(file_name)
root = tree.getroot()
try: tree = ET.parse(file_name)
except ET.ParseError as e:
print("%s: %s: %s" % (sys.argv[0], file_name, e), file = sys.stderr)
continue
else: root = tree.getroot()
try:
channels += [
"%s\n\n" % root.find('{http://www.w3.org/2005/Atom}title').text

View File

@@ -13,9 +13,12 @@ while test -n "$2"; do
else curl=false
fi
filename="$(printf '%s/%s.xml\n' "$directory" "$2")"
if ! $curl "$xml_url_prefix""$2" >"$filename"
then rm -f "$filename"
else printf '%s\n' "$filename"
$curl "$xml_url_prefix""$2" >"$filename".new
if ! grep '<title>' <"$filename".new | head -n 1 \
| grep 404 >/dev/null 2>&1
then mv "$filename".new "$filename" \
&& printf '%s\n' "$filename"
fi
rm -f "$filename".new
shift
done

24
menu.rs
View File

@@ -59,7 +59,7 @@ fn print_entries(entries: &[Entry]) {
eprintln!("");
for (index, entry) in entries.iter().enumerate() {
eprint!(
eprintln!(
"[{:>index_len$}]: {}",
index + 1,
entry.text,
@@ -82,9 +82,7 @@ fn main() -> ExitCode {
}
Ok(file) => Box::new(BufReader::new(file)),
}
} else {
Box::new(io::stdin().lock())
};
} else { Box::new(io::stdin().lock()) };
let user_input: Box<dyn BufRead> = if argv.len() <= 1 {
match File::open("/dev/tty") {
Err(e) => {
@@ -92,9 +90,7 @@ fn main() -> ExitCode {
}
Ok(file) => Box::new(BufReader::new(file)),
}
} else {
Box::new(io::stdin().lock())
}; // ...Oops! I did it again.
} else { Box::new(io::stdin().lock()) }; // ...Oops! I did it again.
// Parser
{
@@ -114,11 +110,11 @@ fn main() -> ExitCode {
}
}
State::Text => {
entry.text = line.clone() + "\n";
entry.text = line.clone();
state = State::Attributes;
}
State::Attributes => {
entry.attr = line.clone() + "\n";
entry.attr = line.clone();
state = State::Content;
}
State::Content => match line.chars().next() {
@@ -160,10 +156,11 @@ fn main() -> ExitCode {
if line != "" {
match line.parse::<usize>() {
Err(e) => {
return error(&argv[0], &line, &e);
eprintln!("{}: Could not parse selection (try 0..{})",
argv[0], entries.len());
}
Ok(n) => {
if n != 0 {
if n != 0 && n <= entries.len() {
match Command::new("sh")
.arg("-c")
.arg(entries[n - 1].cont.clone())
@@ -177,8 +174,9 @@ fn main() -> ExitCode {
Ok(_) => { print_entries(&entries); }
},
}
}
if n == 0 || exit_on_selection {
} else if n > entries.len() {
eprintln!("{}: Selection out of range", argv[0]);
} else if n == 0 || exit_on_selection {
return ExitCode::SUCCESS;
}
}