16 Commits

Author SHA1 Message Date
aa84c33e08 Merge remote-tracking branch 'refs/remotes/origin/fix-paging-bug' into fix-paging-bug 2026-06-18 21:51:46 +00:00
a658151d64 One more shot at cleaning up regexes and fixing the rocket link lines as I want 2026-06-18 21:44:12 +00:00
31b68d9a1f Merge branch 'develop' into fix-paging-bug 2026-06-16 16:40:27 -04:00
4653e5cea5 Update the way links look 2026-06-16 20:38:26 +00:00
b13e6114ba updated help listed in app, in the readme 2026-06-12 17:34:27 -04:00
3abe2517c1 Merge pull request 'Fix paging bug where if you go to a page and scroll down further than a previous (shorter) page can get to, the document is scrolled to bottom and looks empty.' (#6) from fix-paging-bug into develop
Reviewed-on: #6
2026-06-12 17:32:55 -04:00
bec03ff251 Fix paging bug where if you go to a page and scroll down further than a previous (shorter) page can get to, the document is scrolled to bottom and looks empty.
Used AI to figure this out after some back and forth, the 'ypos' function was not obvious.

Ideally I would add a feature that actually tracks the scroll position with the history, so you would go back to the line/page where you came from, preserving previous scrolling. The load (page,1) code in here doesn't reall do that as intended in light of the bugfix discovery.

Also improved the goto_link and goto_page dialog/feature so they handle bogus links and bogus URLs better.
2026-06-12 21:27:39 +00:00
841ad4f858 Merge pull request 'Revert modification to link lines' (#5) from rocket-no-space-bugfix into develop
Reviewed-on: #5
2026-06-09 19:07:21 -04:00
185966f036 Reverted the cutesiness with the link lines. Can't figure out why I can't have => *link* [>count] *link desc* without if there is
no *link desc* that the [] link number ends up on the next line. Reverting for now.
2026-06-09 23:03:54 +00:00
c15052a9da Added a note to remind myself how [^ ] in a regex works 2026-06-09 20:27:43 +00:00
a182b4012c Merge pull request 'Fix for crash that happened if a rocket link had no space after => before path!' (#4) from rocket-no-space-bugfix into develop
Reviewed-on: #4
2026-06-09 16:18:03 -04:00
181322937b Fix for crash that happened if a rocket link had no space after => before path!
Also tried to clean up and match up the regexes to the simplest form.
2026-06-09 20:03:20 +00:00
79bf56de47 added the Perl packages required 2026-06-03 19:06:18 -04:00
895976e0d9 Update README.md 2026-06-03 14:32:33 -04:00
f13660869f added a bit more detail. 2026-06-03 14:24:41 -04:00
6c627e865f Merge pull request 'Adding META files because they are necessary to add packages, I guess' (#3) from uris into develop
Reviewed-on: #3
2024-07-15 13:50:50 -04:00
2 changed files with 168 additions and 50 deletions

View File

@@ -1,3 +1,37 @@
# Connex
A TUI nex browser in perl using Curses
A TUI (terminal UI) nex browser in perl using Curses. See more about the smolnet *Nightfall Express* (nex://) protocol here: https://nightfall.city/nex/
Currently not in one-touch install shape, but you can build it and use it with *cpanm* to get the required libraries.
For all the frippery I added trying to package things the right way for perl, the single script file is just in *scripts/connex.pl* you should be able to run and navigate wherever you'd like in nex-space. ctl-x gets the menu, ">" key lets you choose a link on the page that the browser attaches "[>#]" to mark. "<" navigates back, ctl-q to quit. There is a help dialog accessible from the menu for this meager help:
```
Browsing:
Press '>' key to select a '[>#] link by #
Press '<' key to go back to previous page
Press 'ctl-Y' to see viewed page history
Press 'ctl-P' to see list of links on current page
Scrolling:
Arrow keys to scroll document
Press 'PageDown' to scroll down by page
Press 'PageUp' to scroll up by page
Search:
'less' type search function supported:
Press '/' to start a forward search (type search term, hit <enter>)
search for the next occurance using the 'n' key or the previous
occurance using the 'N' key.
Press '?' to start a reverse search (type search term, hit <enter>)
More Program Features:
Press ctl-x for menu
```
The script needs the following Perl packages:
* FindBin
* Curses::UI
* Net::Telnet
* URI
* URI::Split

View File

@@ -1,9 +1,9 @@
#!/usr/bin/perl -w
# connex.pl Nightfall Express (nex://) browser
# By Pete Dussin, peteyboy@sdf.org 3/2024
# updated 6/2026
# This program uses telnet instead of nc to make nex requests, because I couldn't get the Perl nc module to work right.
#TODO: Fill out help Dialog, mention vi navigatio and search
#TODO: Fill out About Dialog
#TODO: Make status dialog actually useful
#TODO: bookmarks, maybe a quick mark-and-hold toggle to jump between two pages?
@@ -18,6 +18,7 @@ use Curses::UI;
use Net::Telnet;
use URI::Split qw(uri_split uri_join);
use URI ();
use Scalar::Util 'looks_like_number';
use Term::ReadKey; #for fatpacker?
@@ -62,7 +63,7 @@ if (defined $full_url){
die "Need a $SCHEME_NEX url, or start without supplying URL argument.\n";
}
$full_url= $uri->as_string;
$HOME_URL = $full_url; #TODO make sure you want to do this, mostly go home and other defaults will go here instead o nightfall.city
$HOME_URL = $full_url; #TODO make sure you want to do this, mostly go home and other defaults will go here instead of nightfall.city
}else{
$full_url = $HOME_URL;
}
@@ -84,19 +85,19 @@ my $connect = new Net::Telnet (Timeout => 10,
my @menu = (
{ -label => 'File',
-submenu => [
{ -label => 'Choose Link >', -value => \&goto_link_dialog },
{ -label => 'Back ^B/<', -value => \&goto_back },
{ -label => 'Go to Link ^G', -value => \&navigate_link_dialog },
{ -label => 'Go Home ^M', -value => \&goto_home },
{ -label => 'Page Links ^P', -value => \&page_links_dialog },
{ -label => 'History ^Y', -value => \&history_status_dialog },
{ -label => 'Exit ^Q', -value => \&exit_dialog }
{ -label => 'Choose Link >', -value => \&goto_link_dialog },
{ -label => 'Back ^B/<', -value => \&goto_back },
{ -label => 'Go to Link ^G', -value => \&navigate_link_dialog },
{ -label => 'Go Home ^M', -value => \&goto_home },
{ -label => 'Page Links ^P', -value => \&page_links_dialog },
{ -label => 'Browser History ^Y', -value => \&history_status_dialog },
{ -label => 'Exit ^Q', -value => \&exit_dialog }
]
},
{ -label => 'Help',
-submenu => [
{ -label => 'Help ^H', -value => \&help_dialog },
{ -label => 'About ', -value => \&about_dialog },
{ -label => 'Help ^H', -value => \&help_dialog },
{ -label => 'About ', -value => \&about_dialog },
]
},
@@ -108,7 +109,7 @@ my @menu = (
sub exit_dialog()
{
my $return = $cui->dialog(
-title => "Quit Connex?",
-title => "Quit Connex",
-message => "Are you sure?",
-buttons => ['yes', 'no'],
@@ -132,6 +133,9 @@ sub links_dialog()
sub unsupported_dialog
{
my $scheme = shift;
if (!defined $scheme){
$scheme="unknown";
}
my $return = $cui->dialog(
-message => "$scheme protocol not supported.",
-title => "Bad Navigation",
@@ -159,16 +163,19 @@ sub goto_link_dialog()
);
#if not canceled, or too big or too small, goto link
if($return){
my $linkcount = scalar @page_links;
if($return <= $linkcount && $return >0){
update_status($S_REQUESTING);
goto_link($return);
}else{
#$browser->focus();
my $return1 = $cui->status("there is no link # " . $return);
if(looks_like_number($return)){
my $linkcount = scalar @page_links;
if($return <= $linkcount && $return >0){
update_status($S_REQUESTING);
goto_link($return);
}else{
my $return1 = $cui->status("there is no link # " . $return);
}
}else{ #they are using it to navigate to a different site or for some other reason entered text
my $return2 = $cui->status("You did not enter a link #. To Go to a different site, use 'Go' menu or type ctl-g");
}
#do nothing on cancel
}
#do nothing on cancel
}
@@ -182,7 +189,7 @@ sub goto_back()
#if($fetched) {
$full_url =$fetched;
update_status($S_REQUESTING);
load($full_url,0); #don't move back to top
load($full_url,1); #move back to top
history_status_dialog();
#}
@@ -198,7 +205,7 @@ sub goto_home()
$full_url=$HOME_URL;
}
update_status($S_REQUESTING);
load($full_url,0); #don't move back to top
load($full_url,1); #move back to top
history_status_dialog();
}
@@ -211,7 +218,7 @@ sub goto_link{
#my $element=$linknum -1; #offset for array element
#if ($element <= $#page_links){ #such a perlism, this is highest INDEX of array
if ($linknum <= $linkcount){ #such a perlism, this is highest INDEX of array
if ($linknum <= $linkcount){
navigate($page_links[$linknum-1]); #offset from count to index
}else{
#my $browser = $win1->getobj("browser");
@@ -231,6 +238,15 @@ sub navigate{
}
sub browser_scroll_reset
{
my $browser = $win1->getobj("browser");
$browser->{-ypos} = 0;
#$browser->{-viewPos} =0; none of this works
$browser->draw();
$browser->focus();
}
sub update_status_bar
{
my $status = shift;
@@ -291,12 +307,16 @@ sub history_status_dialog
sub page_links_dialog
{
my $browser = $win1->getobj("browser");
$browser->focus();
#my $link_list = join("\n", @page_links);
if(@page_links){
my $browser = $win1->getobj("browser");
$browser->focus();
#my $link_list = join("\n", @page_links);
my $link_list = page_links_list();
my $return = $cui->status("links on this page:\n$link_list");
#}elsif (!is_path_index($browser->title())){ #if not an index, actually is this even important to the user?
# my $return = $cui->status("Not an index page.");
}else{ #there are no links in this index (should be rare, and index with no links?)
my $return = $cui->status("No links on this page.");
}
}
@@ -312,7 +332,7 @@ sub page_links_list
my $count=0;
foreach $link (@page_links){
$count+=1;
$link_list = $link_list . "[$count] $link\n";
$link_list = $link_list . "[>$count] $link\n";
}
return $link_list;
}
@@ -330,12 +350,27 @@ sub help_dialog
my $browser = $win1->getobj("browser");
$browser->focus();
my $message = <<'END_MESSAGE';
Navigation:
Press '>' key to select a '[>#]link by #
Browsing:
Press '>' key to select a '[>#] link by #
Press '<' key to go back to previous page
Press 'ctl-Y' to see viewed page history
Press 'ctl-P' to see list of links on current page
Program Features:
Scrolling:
Arrow keys to scroll document
Press 'PageDown' to scroll down by page
Press 'PageUp' to scroll up by page
Search:
'less' type search function supported:
Press '/' to start a forward search (type search term, hit <enter>)
search for the next occurance using the 'n' key or the previous
occurance using the 'N' key.
Press '?' to start a reverse search (type search term, hit <enter>)
More Program Features:
Press ctl-x for menu
END_MESSAGE
my $return = $cui->dialog(
@@ -397,6 +432,7 @@ $statusbar = $win1->add("status", "TextViewer",
#key bindings, should match menu items
$cui->set_binding(sub {$menu->focus()}, "\cX");
$cui->set_binding( \&help_dialog , "\cH");
$cui->set_binding( \&exit_dialog , "\cQ");
$cui->set_binding( \&navigate_link_dialog , "\cG");
$cui->set_binding( \&goto_back , "\cB");
@@ -405,7 +441,6 @@ $cui->set_binding( \&goto_link_dialog , ">");
$cui->set_binding( \&goto_home , "\cM");
$cui->set_binding( \&page_links_dialog , "\cP");
$cui->set_binding( \&history_status_dialog , "\cY");
$cui->set_binding( \&help_dialog , "\cH");
$cui->set_binding(sub {
my $cui = shift;
$cui->layout;
@@ -453,22 +488,59 @@ sub is_path_index{
return($result);
}
sub add_page_link{
my $linkline = shift;
my $base_url = shift;
my $uri_object;
#sub add_page_link{
# my $linkline = shift;
# my $base_url = shift;
# my $uri_object;
#my $link= $linkline=~ s/^=>[ ]*(.*$)/$1/r;
local $URI::ABS_ALLOW_RELATIVE_SCHEME = 1;
local $URI::ABS_REMOTE_LEADING_DOTS = 1;
$uri_object=URI->new_abs($linkline=~ /^=>[ ]+([^ ]*)/,$base_url);
push(@page_links, $uri_object->as_string);
my $count = scalar @page_links; #scalar is size/count of links, but $#page_links is highest INDEX
return $linkline =~ s/(^=>.*$)/$1 [\>$count\]/r;
# local $URI::ABS_ALLOW_RELATIVE_SCHEME = 1;
# local $URI::ABS_REMOTE_LEADING_DOTS = 1;
# $uri_object=URI->new_abs($linkline=~ /^=>[ ]+([^ ]*)/,$base_url);
#
# push(@page_links, $uri_object->as_string);
# my $count = scalar @page_links; #scalar is size/count of links, but $#page_links is highest INDEX
# return $linkline =~ s/(^=>.*$)/$1 [\>$count\]/r;
#}
sub add_page_link{
my $linkline = shift;
my $base_url = shift;
my $uri_object;
my $uritext;
my $description;
local $URI::ABS_ALLOW_RELATIVE_SCHEME = 1;
local $URI::ABS_REMOTE_LEADING_DOTS = 1;
#remember inside of braces, ^ means NOT, so any NOT SPACE letters are selected, so everything up to next space
if ($linkline=~ /^=> ([^ ]*)/){ #has to be something here or I think URI->new_abs has exception that crashes app
$uri_object=URI->new_abs($linkline=~ /^=> ([^ ]*)/,$base_url);
$uritext = ($linkline=~ s/^=> ([^ ]*).*/$1/r);
chomp($uritext);
push(@page_links, $uri_object->as_string);
my $count = scalar @page_links; #scalar is size/count of links, but $#page_links is highest INDEX
#below puts the [>1] at the end of the description.
#return $linkline =~ s/(^=>.*$)/$1 [\>$count\]/r; don't need to escape on the replace part of a substitution, I guess?
#below puts the [>1] at the beginning of line, replacing =>
#return $linkline =~ s/^=>/[>$count]/r;
#This reconstructs the uri so it can put the [>1] between the uri and the description, but still on the same
#line as the url, if there isn't a description (was unable to figure out how to do in one regex!)
if ($linkline =~ /=> .* [^\n]+/){
$description = ($linkline=~ s/=> [^ ]+ ([^\n]+)/$1/r);
}
else{
$description= "";
}
return "=> " . $uritext . " [>$count] " . $description . "\n";
}else{
return $linkline;
}
}
#=== NEX REQUESTS AND RESPONSE PROCESSING ===
sub load
{
@@ -489,12 +561,26 @@ sub load
$connect->port($port);
$ok= $connect->open($host);
$ok= $connect->print($path);
#TODO: What if it's not a text file? We need to check and have a download prompt and download if it's not text!
@lines =$connect->getlines(ErrMode=> 'return');
print $connect->eof();
#TODO:handle non-existant request? Die is not pretty to do here
#TODO:handle non-existent request? Die is not pretty to do here
die unless $connect->eof();
$connect->close();
my $widget= $texteditor;
# check if we want to scroll to top
if ($top eq 1){
#For widget programmers: To control the scrollbar, the widget data -vscrolllen (the total length of the content of the widget) and -vscrollpos (the current position in the document) should be set.
# If Curses::UI::Widget::draw is called, the scrollbar will be drawn.
#browser_scroll_reset();
#my $browser = $win1->getobj("browser");
$widget->{-ypos} = 0;
#$browser->{-viewPos} =0; none of this works
#$browser->draw();
#$browser->focus();
}
#loop through nex response and load into text editor. Identify, mark and store link lines for index pages
my $page_contents =""; #this is the page contents to be dumped into the browser widget
@@ -503,18 +589,16 @@ sub load
my $is_index= is_path_index($path);
undef @page_links; #clear list
foreach $currentline (@lines){
if ($currentline =~ m/^=>/){
if ($is_index){
if ($is_index){ #only do this for index pages
if ($currentline =~ m/^=> /){ #check for valid rocket link with space
$currentline = add_page_link($currentline, $url);
}
}
$page_contents= $page_contents . $currentline;
}
$widget->text($page_contents);
$widget->text($page_contents);
$widget->draw();
if ($top){
$widget->pos(0);
}
if ($page_contents eq ''){
update_status($S_NORESPONSE);
}else{