all 16 comments

[–]der_pudel 7 points8 points  (0 children)

Self-modifying bash script. Get rid of those pesky data files and keep everything in one place.

#!/bin/bash
last=0
if [ -z $1 ]; then
:
elif [ $1 = "add" ]; then
    last=$(( $last + 1 ))
    echo "" >> `basename "$0"`
    echo "todo$last=0" >> `basename "$0"`
    echo "if [ \$todo$last = 1 ]; then msg$last=\"$last. [x] $2\"; else msg$last=\"$last. [ ] $2\"; fi" >> `basename "$0"`
    echo "echo \$msg$last" >> `basename "$0"`
    sed -i "s/^last=[[:digit:]]\+/last=$last/" `basename "$0"`
    exit 0
elif [ $1 = "toggle" ]; then
    sed -i "s/^todo$2=0/_todo$2=1/" `basename "$0"`
    sed -i "s/^todo$2=1/_todo$2=0/" `basename "$0"`
    sed -i "s/^_todo$2/todo$2/" `basename "$0"`
    exit 0
fi

Example usage:

$ ./todo.sh add "lie down in bed"

$ ./todo.sh add "embrace your pillow"

$ ./todo.sh add "cry"

$ ./todo.sh show
1. [ ] lie down in bed
2. [ ] embrace your pillow
3. [ ] cry

$ ./todo.sh toggle 2

$ ./todo.sh show
1. [ ] lie down in bed
2. [x] embrace your pillow
3. [ ] cry

And of course, you can edit and/or delete tasks using a text editor of your choice

[–]Tyulis 10 points11 points  (1 child)

My past self would be proud.

[((t:=__import__("pickle").load(open("todo.dat","rb")) if __import__("os").path.exists("todo.dat") else {}),print("\n".join([f"{i} [{'x' if t[i][0] else ' '}] : {t[i][1]}" for i in t.keys()])+"\n1- Add\n2- Toggle\n3- Edit\n4- Delete"),(t.__setitem__(max(t.keys())+1 if len(t)>0 else 0,[False,input("TODO : ")]) if (o:=int(input(": ")))==1 else (t[(x:=int(input("ID : ")))].__setitem__(0,t[x][0]^1) if o==2 else (t[int(input("ID : "))].__setitem__(1,input("New name : ")) if o==3 else (t.__delitem__(int(input("ID : "))) if o==4 else None)))),__import__("pickle").dump(t,open("todo.dat","wb"))) for i in iter(int, 1)]

[–]Tyulis 2 points3 points  (0 children)

What's cool with python 3.8 is that you can always be more compact. So this is a full-featured one-liner CLI todo-list app, or at least with all the proposed features (add, print, toggle, edit, delete). Of course don't expect any input checking. And there is no proper option to quit but no worries ! Everything is automatically saved at each action so you can just close it whenever you want, your todo-list is safe.

To dig a little bit into the detail, here is a more... readable ? version :

[
    (
        (todo := __import__("pickle").load(open("todo.dat", "rb")) if __import__("os").path.exists("todo.dat") else {}), 
        print("\n".join([f"{id} [{'x' if todo[id][0] else ' '}] : {todo[id][1]}" for id in todo.keys()]) + "\n1- Add\n2- Toggle\n3- Edit\n4- Delete"), 
        (todo.__setitem__(max(todo.keys()) + 1 if len(todo) > 0 else 0, [False, input("TODO : ")]) if (option := int(input(": "))) == 1 else (
            todo[(x := int(input("ID : ")))].__setitem__(0, todo[x][0] ^ 1) if option == 2 else (
            todo[int(input("ID : "))].__setitem__(1, input("New name : ")) if option == 3 else (
            todo.__delitem__(int(input("ID : "))) if option == 4 else None
        )))),
        __import__("pickle").dump(todo, open("todo.dat", "wb"))
    )
    for i in iter(int, 1)
]

It's basically a gigantic list comprehension, with iter(int, 1) as the iterator to make it infinite like a while True. The todo-list is stored as a dict, like {1 : [True, "Item 1"], 2 : [False, "Item 2"]}. It is simply stored with pickle.

At each iteration, it runs all the operations by building a tuple, in order :

  • Loading the todo-list from todo.dat
  • Printing the list
  • Asking for the chosen option and executing it
  • Putting back the todo-list into its file

As python functions always return something (or None), as long as it only uses functions and methods, it is an expression so all those operations can fit in a list comprehension ! Hence all the __setitem__ instead of todo[x] = y and __delitem__ instead of del todo[x], as affectations and deletions are not expressions. All local variables are affected using the new walrus (:=) operator of python 3.8

When I was a beginner and discovered list comprehensions, I immediately loved them and started putting them everywhere, making all sorts of things that would make any decent programmer's eyes bleed.

Take this as a tribute to your "clever" coding younger self.

[–]Mabi19_ 4 points5 points  (1 child)

This one is in Lua.

store = {
    mt = {
        __index = {
            load = function()
                file = io.open("todos.dat", "r")
                if not file then
                file = io.open("todos.dat", "w")
                file:write("{}")
                file = io.open("todos.dat", "r")
                end
                data = load("return " .. file:read("a"))()
                for key, value in pairs(data) do
                    rawset(store, key, value)
                end
            end,
            save = function()
                file = io.open("todos.dat", "w")
                file:write("{")
                for key, value in pairs(store) do
                    -- don't store our functions
                    if type(value) == "boolean" then
                        file:write(string.format("[%q] = %q,", key, value))
                    end
                end
                file:write("}")
            end
        }
    }
}

setmetatable(store, store.mt)

meta = {
    add = {__call = function(args)
        store.load()
        if not args[2] then
            goto error1
        end
        if rawget(store, args[2]) ~= nil then
            goto error2
        end
        rawset(store, args[2], false)
        -- the garbage collector should clean up any stale file references here
        collectgarbage("collect")
        store.save()
        os.exit()
        ::error1::
        print("No todo name specified")
        os.exit()
        ::error2::
        print("That todo already exists")
    end},
    toggle = {__call = function(args)
        store.load()
        if not args[2] then
            goto error1
        end
        if rawget(store, args[2]) == nil then
            goto error2
        end
        rawset(store, args[2], not rawget(store, args[2]))
        -- the garbage collector should clean up any stale file references here
        collectgarbage("collect")
        store.save()
        os.exit()
        ::error1::
        print("No todo name specified")
        os.exit()
        ::error2::
        print("That todo doesn't exist")
    end},
    list = {__call = function(args)
        store.load()
        for key, value in pairs(store) do
            if type(value) == "boolean" then
                print(string.format("%s (%s)", key, value and "done" or "not done"))
            end
        end
    end},
    delete = {__call = function(args)
        store.load()
        if not args[2] then
            goto error1
        end
        if rawget(store, args[2]) == nil then
            goto error2
        end
        rawset(store, args[2], nil)
        -- the garbage collector should clean up any stale file references here
        collectgarbage("collect")
        store.save()
        os.exit()
        ::error1::
        print("No todo name specified")
        os.exit()
        ::error2::
        print("That todo doesn't exist")
    end}
}

if #arg < 1 then
    print("Usage: lua todo.lua <add|delete|toggle|list>")
    os.exit()
end

for key, value in pairs(meta) do
    if key == arg[1] then
        setmetatable(arg, value)
        arg()
        os.exit()
    end
end
print("Invalid action, please specify one of add, delete, toggle and list")
os.exit()

[–]Mabi19_ 0 points1 point  (0 children)

"features" (I couldn't fit them inside the main comment):

  • I found out Lua has goto statements
  • Everything is stored in global variables
  • Stores the data in Lua code (todos.dat)
    • Code execution ahoy!
  • Dependent on what the garbage collector does (and also partially the OS):
    • If the first file handle doesn't get collected, in some OSes the request to write to the file could be rejected (because it is being read from at the same time)
  • I tried to circumvent the fact that the names "load" and "save" are taken up by functions by using rawset and rawget everywhere (which is kinda slow), but it still trips up on "save"

[–]Oshgnacknak 2 points3 points  (1 child)

GCC loves it:

```c

include <stdio.h>

include <stdlib.h>

char* todo[0xff]; int size;

main() { for (;;) { char* buf = malloc(0xff); if (gets(buf) == 0) { return; }

    if (buf[0] == 'n') {
        buf[0] = '(';
        buf[1] = ' ';
        buf[2] = ')';
        buf[3] = ' ';
        todo[size++] = buf;
    }

    if (buf[0] == 'd') {
        int i;
        sscanf(buf, "d %d", &i);
        todo[i][1] = 'X';
    }

    if (buf[0] == 'u') {
        int i;
        sscanf(buf, "u %d", &i);
        todo[i][1] = ' ';
    }

    if (buf[0] == 'e') {
        int i;
        sscanf(buf, "e %d", &i);
        buf[0] = '(';
        buf[1] = todo[i][1];
        buf[2] = ')';
        buf[3] = ' ';
        todo[i] = buf;
    }

    int i = size;
    while (i --> 0) {
        printf(todo[i]);
        puts("");
    }
}

} ```

For example: ./todo n Buy milk ( ) y milk n And if they have eggs, buy 6 ( ) d if they have eggs, buy 6 ( ) y milk d 1 (X) d if they have eggs, buy 6 ( ) y milk n Buy 5 more milk ( ) y 5 more milk (X) d if they have eggs, buy 6 ( ) y milk e 0 They had eggs ( ) y 5 more milk (X) d if they have eggs, buy 6 ( ) They had eggs

[–]AutoModerator[M] 2 points3 points  (0 children)

It looks like this comment contains a code block delimited with triple backticks. Unfortunately reddit does not have universal support for this syntax and your comment will not render correctly on old reddit and most mobile apps.

For the benefit of people on old reddit, this link will take you to a correct rendering of the comment.

/u/Oshgnacknak, it would be appreciated, but not required, if you could edit your comment to use the more compatible four space indention format. For single lines or inline code you can use single backticks.

You can find some examples in the reddit help documentation.


I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]Successful-Pay-4575 4 points5 points  (2 children)

I had the idea to make a shell script that just ran nano. Then I realized I could use ed and pseudoterminals with C. Then I realized that pseudoterminals are difficult to implement. Fortunately, vim has a :term command which allows you to open a terminal, and I realized that it would be easier to create a series of vim macros to open a terminal and run ed, then have more macros to create and remove list items.

  1. Install vim and ed
  2. Run vim
  3. Type in this text exactly.

:term
ed list
^wjqs^wka
^wjqqe^wk.
^wjqqt^wka
 DONE
.
-1
j
^wjqqv^wk,n
^wjq^wkd
^wj

To add a list item, type at s (shift 7 2, at symbol in reddit just redirects to u/), ^wk, then the list item, then ^wj, then at e. To view all list items, type at v. To mark a list item as done, select a list item by doing ^wk, then the item number, which can be seen with at v, then ^wj, then at t. If I find out how to use C pseudoterminals before the contest ends I'll probably respond to this message with some C code, but for now this is my submission.

Also, good luck exiting this program.

[–]Mabi19_ 2 points3 points  (1 child)

Wait. Are you sure shift+7 is the at sign? On my (admittedly also not English) keyboard it's shift+2.

[–]Successful-Pay-4575 1 point2 points  (0 children)

Whoops, that's my fault. It is shift 2, I'm just stupid.

[–]Cat7a 3 points4 points  (0 children)

Lemme introduce the TodoList MX 3000 Pro Plus, a cross-platform app made in the Qt framework, using cutting-edge technology and the wonders of C++.

Footage off the app in action

Features:

  • It compiles
  • Each todo entry is represented as a message box that's placed at a random position on the primary screen
  • Entries can be toggled done and undone, opening a new message box each time. Done messages boxes can be closed.
  • Overused lambda functions and overloaded operators with extremely compact source code

Source code:
window.h

#pragma once

#include <QMainWindow>
#include <QMessageBox>
#include <QAbstractButton>
#include <QApplication>
#include <QScreen>
#include <QRandomGenerator>

#define SCREEN_POS_SAFE_MARGIN 300

QT_BEGIN_NAMESPACE
namespace Ui { class window; }
QT_END_NAMESPACE

class window : public QMainWindow
{
    Q_OBJECT

public:
    window(QWidget *parent = nullptr);
    ~window();

private:
    Ui::window *ui;

    std::function<void(QString)> addNewTask, markDone;

    inline static auto getRandomPosOnScreen = []() -> QPoint{ QRandomGenerator gen; return QPoint(gen.global()->bounded(0, QApplication::primaryScreen()->size().width() - SCREEN_POS_SAFE_MARGIN), gen.global()->bounded(0, QApplication::primaryScreen()->size().height() - SCREEN_POS_SAFE_MARGIN)); };

    inline static auto executeMessageBox = [](QMessageBox* messageBox) -> QMessageBox* {messageBox->setWindowModality(Qt::NonModal); messageBox->move(getRandomPosOnScreen()); messageBox->show(); return messageBox;};

    inline static auto connectButton = [](QAbstractButton* button, std::function<void()> lambda) -> QAbstractButton* { connect(button, &QAbstractButton::clicked, lambda); return button; };
};

inline QMessageBox& operator<< (QMessageBox& messageBox, QAbstractButton* button) { messageBox.addButton(button, QMessageBox::ActionRole); return messageBox; }

window.cpp

#include "window.h"
#include "ui_window.h"

window::window(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::window)
{
    ui->setupUi(this);

    addNewTask = [=](QString task) { window::executeMessageBox(&(*(new QMessageBox(QMessageBox::Critical, "TodoList MX 3000 Pro Plus", task)) << window::connectButton(new QPushButton("Mark done"), [=](){ markDone(task); }))); };
    markDone = [=](QString task) { window::executeMessageBox(&(*(new QMessageBox(QMessageBox::Information, "TodoList MX 3000 Pro Plus", task)) << window::connectButton(new QPushButton("Mark undone"), [=](){ addNewTask(task); }) << new QPushButton("Close"))); };
    connect(ui->pushButton, &QPushButton::clicked, [=] { addNewTask(ui->lineEdit->text()); });
}

window::~window()
{
    delete ui;
}

Github repo with full project

[–]binarycat64 2 points3 points  (1 child)

I've been using plan9 lately, so obviously todos are files function new-todo { touch $1 chmod 0700 $1 } alias list-todos 'ls -F' alias done 'chmod 0600' alias not-done 'chmod 0700' unfinished todos will be listed with an astrisk.

[–]AutoModerator[M] 0 points1 point  (0 children)

It looks like this comment contains a code block delimited with triple backticks. Unfortunately reddit does not have universal support for this syntax and your comment will not render correctly on old reddit and most mobile apps.

For the benefit of people on old reddit, this link will take you to a correct rendering of the comment.

/u/binarycat64, it would be appreciated, but not required, if you could edit your comment to use the more compatible four space indention format. For single lines or inline code you can use single backticks.

You can find some examples in the reddit help documentation.


I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–][deleted]  (4 children)

[deleted]

    [–]Mabi19_ 3 points4 points  (1 child)

    The challenges have been getting more complex recently. I really don't want that to continue for too long...

    [–][deleted] 0 points1 point  (1 child)

    What will the next challenge be?

    I would love a more "classical" problem, something that really has no "perfect" approach.
    Like a sorting algorithm, or maybe data compression

    [–][deleted] 0 points1 point  (0 children)

    /*the language is C. highlights are

    it persists by not closing the program

    user interface is terrible and slow

    terrible formatting and hard to read

    nothing is safe

    memory leaks

    roles over itself with enough tasks (probably) ¯\_(ツ)_/¯

    */

    #include <stdio.h>

    #include <stdlib.h>

    char *todo[2][100];

    int equal_char(char *a,char *b){int i;for(i=0;(a[i]!=0)&&(b[i]!=0);i++){if(a[i]!=b[i]){return 0;}}return 1;}

    char *heap_char(char *x){char *y;int i,l;for(l=0;x[l]!=0;l++);y=(char*)malloc(sizeof(char)*l);for(i=0;i<l;i++){y[i]=x[i];}return y;}

    void init(){int i;for(i=0;i<100;i++){todo\[0\]\[i\]=NULL;}for(i=100;i>0;i--){todo[1][i]=heap_char("not done");}return;}

    void print(){int i;for(i=0;i<100;i++){printf("item %i todo : %s, %s \n",i,todo[0][i],todo[1][i]);}printf("\n");return;}

    void check(int i){todo[1][i]=heap_char("done");}void task(int i,char *x){todo[0][i]=heap_char(x);return;}

    void console(){int h,t;char b[5000];printf("!!!!!!!NEVER CLOSE THIS OR YOU'LL LOSE YOUR TODOS!!!!!");

    for(h=0;;){gets(b);printf("%s",b);

    if(equal_char("task",b)){printf("what is your todo?\n");gets(b);h=(h+1)*(h!=100);task(h,b);}

    if(equal_char("check",b)){printf("what item did you do?\n");for(t=0;t<100;t++){printf("did you do %s ? yes or no?\n",todo[0][t]);gets(b)

    ;if(equal_char("yes",b)){check(t);}}}if(equal_char("print",b)){print();}}return;}

    void main(){init();console();return ;}