Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fails with marquee text #10

Closed
trappedinspacetime opened this issue Jan 18, 2022 · 12 comments
Closed

Fails with marquee text #10

trappedinspacetime opened this issue Jan 18, 2022 · 12 comments

Comments

@trappedinspacetime
Copy link

trappedinspacetime commented Jan 18, 2022

First of all, I congratulate you on your project. It works great except with marquee text.
I have below script which scrolls rss news feeds from right to left in terminal. But unfortunately it fails.

 while true;do n="$(curl -s https://news.yahoo.com/rss/|sed 's/</\n/g'|grep "title>"|sed -e '/^\// d' -e 's/title>/---------- /g' -e '1,3d'|tr '\n' ' ')";for i in $(eval echo {0..${#n}});do echo -ne "\e[s\e[0;0H${n:$i:$COLUMNS}\e[u";sleep .15;printf \\033c;done;done

I couldn't wrap my head around it.

@sineemore
Copy link
Owner

sineemore commented Jan 18, 2022 via email

@sineemore
Copy link
Owner

sineemore commented Jan 18, 2022

Here is a simple example:

#!/bin/bash

set -eu

pad="                    "
text="${pad}Very long text should scroll like <marquee> did.${pad}"

pad_size="${#pad}"
text_size="${#text}"

i=1
while [ $(( i + pad_size )) -le $text_size ]
do
    printf "${text:i:pad_size}"
    printf '\n\004\n'
    i=$(( i + 1 ))
    sleep 0.1
done

Save file as marquee.sh, make it executable and run with stw -t -x10 -y-10 ./marquee.sh

Notice the usage of printf '\n\004\n'. This line in output tells stw to render collected text and wait next frame.

https://github.com/sineemore/stw/blob/master/config.h#L26

Also, watch out for CPU usage, sleep command is not a builtin one. Probably it's better to write this script in Perl, Python, etc to save that forks and avoid scripting in bash :)

@sineemore
Copy link
Owner

sineemore commented Jan 18, 2022

Here is a marquee helper example in Go, you can compile it with go build -o marquee-helper filename.go:

package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"
	"time"
)

const stwFlushFrame = "\n\004\n"

func main() {
	width := flag.Int("w", 20, "output width")
	sleep := flag.Duration("s", 100*time.Millisecond, "amount of sleep after each output")
	flag.Parse()

	pad := strings.Repeat(" ", *width)

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {

		text := pad + scanner.Text() + pad
		for i := 0; i <= len(text)-len(pad); i += 1 {

			fmt.Print(text[i : i+*width])
			fmt.Print(stwFlushFrame)

			if *sleep != 0 {
				time.Sleep(*sleep)
			}
		}
	}
}

Try it with

stw -t -F'monospace:size=54' -bblack -flime sh -c 'seq 1 10 | ./marquee-helper -w 20 -s 10ms'

It runs at 100 FPS with near 0 CPU usage. At least on my machine -.-

@trappedinspacetime
Copy link
Author

@sineemore Thank you for your help. Both of them works well, but as you stated go marquee-helper is better. You are a good instructor.
I still have method confusion. Shall I download rss feeds into a file and cat it to stw?

@sineemore
Copy link
Owner

sineemore commented Jan 19, 2022

IIUC, you need something like this:

#!/bin/sh

set -eu

# params
marquee_helper=~/x/stw-samples/marquee-helper # path to marquee-helper Go binary
width=100                                     # marquee width
sleep=100ms                                   # animation speed
update_period=$(( 60 * 60 * 1 ))              # update rss text every 1 hour

rssline() {
    curl -s https://news.yahoo.com/rss/ \
    | sed 's/</\n/g' \
    | grep "title>" \
    | sed -e '/^\// d' -e 's/title>/---------- /g' -e '1,3d' \
    | tr '\n' ' '
}

unixtime() {
    date +%s
}

text="$(rssline)"
last="$(unixtime)"

while :
do
    echo loop >&2
    now="$(unixtime)"
    if [ $(( last + update_period )) -lt "$now" ]
    then
        text="$(rssline)"
        last="$now"
        echo update >&2
    fi

    printf '%s' "$text" | "$marquee_helper" -w "$width" -s "$sleep"
done

Set valid params in the script and run with stw:

stw ./rss.sh

@trappedinspacetime
Copy link
Author

@sineemore I am grateful for all your help. You spent time for me. It works well.
All the best.

@trappedinspacetime
Copy link
Author

@sineemore in go marquee_helper text flickers now and then but I think I can handle it.

@sineemore
Copy link
Owner

Btw, while I've tested RSS script I've found, that clicks won't restart shell script immediately when it is a long running process. Fixed it in master.

Clicking stw window is a hack to immediately restart subcommand (for example to get latest RSS content in your case). I use clicks to skip waiting another minute and update pstree output on my desktop.

@trappedinspacetime
Copy link
Author

@sineemore I tested your latest push. Thanks, it works well.
Regarding the flikering of the marquee text, I recorded the following clip from my screen. I haven't figured out if it's related to marquee_helper.

output2.mp4

@trappedinspacetime
Copy link
Author

Since I was not able to fix flickering issue with marquee_helper.go I decided to use your bash way. But I hit printf: --: invalid option bug. Luckily replacing printf with /usr/bin/printf works around the bug.

      #!/bin/bash
      
      set -eu
      rssline() {
          curl -s https://www.gercekgundem.com/rss/ \
          | sed 's/</\n/g' \
          | grep "title>" \
          | sed -e '/^\// d' -e 's/title>/---------- /g' -e '1,3d' \
          | tr '\n' ' '
      }
      
      pad="                                                                                                                      "
      rtext="$(rssline)"     
      text="$pad$rtext$pad"            
      #text="${pad}Very long text should scroll like <marquee> did.${pad}"
      
      pad_size="${#pad}"
      text_size="${#text}"
      
      i=1
      while [ $(( i + pad_size )) -le $text_size ]
      do
          /usr/bin/printf "${text:i:pad_size}"
          /usr/bin/printf '\n\004\n'
          i=$(( i + 1 ))
          sleep 0.1
      done

@sineemore
Copy link
Owner

sineemore commented Jan 21, 2022

printf failed when "${text:i:pad_size}" evaluated to "--...". You can fix it with printf -- "${text:i:pad_size}".

https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html

Check Guideline 10 at the bottom of the page.

@trappedinspacetime
Copy link
Author

@sineemore Thank you for the info. bash scripting is sometimes tricky.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants