diff --git a/joy/gui/default_joy_home/definitions.txt b/joy/gui/default_joy_home/definitions.txt new file mode 100644 index 0000000..97e2cae --- /dev/null +++ b/joy/gui/default_joy_home/definitions.txt @@ -0,0 +1,17 @@ +see_stack == good_viewer_location open_stack +see_resources == list_resources good_viewer_location open_viewer +open_resource_at_good_location == good_viewer_location open_resource +see_log == "log.txt" open_resource_at_good_location +see_definitions == "definitions.txt" open_resource_at_good_location +round_to_cents == 100 * ++ floor 100 / +reset_log == "del log.lines[1:] ; log.at_line = 0" evaluate +see_menu == "menu.txt" good_viewer_location open_resource + +# Ordered Binary Tree datastructure functions. +BTree-new == swap [[] []] cons cons + _BTree-P == over [popop popop first] nullary + _BTree-T> == [cons cons dipdd] cons cons cons infra + _BTree-T< == [cons cons dipd] cons cons cons infra + _BTree-E == pop swap roll< rest rest cons cons + _BTree-recur == _BTree-P [_BTree-T>] [_BTree-E] [_BTree-T<] cmp +BTree-add == [popop not] [[pop] dipd BTree-new] [] [_BTree-recur] genrec diff --git a/joy/gui/default_joy_home/log.txt b/joy/gui/default_joy_home/log.txt new file mode 100644 index 0000000..a0d63f8 --- /dev/null +++ b/joy/gui/default_joy_home/log.txt @@ -0,0 +1,4 @@ +Joypy - Copyright © 2018 Simon Forman +This program comes with ABSOLUTELY NO WARRANTY; for details right-click "warranty". This is free software, and you are welcome to redistribute it under certain conditions; right-click "sharing" for details. Right-click on these commands to see docs on UI commands: key_bindings mouse_bindings + + <- diff --git a/joy/gui/default_joy_home/scratch.txt b/joy/gui/default_joy_home/scratch.txt new file mode 100644 index 0000000..68a1935 --- /dev/null +++ b/joy/gui/default_joy_home/scratch.txt @@ -0,0 +1,120 @@ +reset_log words mouse_bindings key_bindings + +Stack Chatter + + dup dupd dupdd over tuck + pop popd popdd popop popopd popopdd + swap roll< roll> rolldown rollup + unit clear + +Math + + add + sub - mul * truediv / mod % + div divmod floor pm + abs sqr sqrt neg pow + max min sum average product + pred -- succ ++ lshift << rshift >> + +Logic + + ge gt eq le lt ne + < <= = >= > != <> + and & or not xor ^ + bool truthy ? + +Combinators + + i x b infra dip dipd dipdd dupdip dupdipd + cleave fork app1 app2 app3 map pam + nullary unary binary ternary + +Control Flow + + branch cond ifte choice + loop while genrec primrec + make_generator + +List Manipulation + + enstacken disenstacken stack unstack + first first_two second third fourth rest rrest + flatten drop take reverse select zip + size sort shunt getitem + step step_zero times + cons ccons uncons swons unswons + concat unique + remove + at of pick + unquoted quoted + +Misc + + down_to_zero cmp gcd help id + least_fraction parse quoted + range range_to_zero + reset_log show_log + run + stuncons stununcons + swaack + void + + +[ ] Add logging? +[ ] INI file? +[ ] definitions.txt +[ ] Integrate inference +[ ] command to (re-)run with trace +[ ] Backtime button? + + +------------------------------------------ +[23 18] [unit i] + +sqr foo == uncons mul + + swaack + + over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 + +5 sqrt 2 / 0.5 + +5 sqrt 1 + 2 / +phi == 5 sqrt ++ 2 / +phi == 1.618033988749895 +(But this is Lambda Abstaction sneaking in the back door.) += +clear + +(n1 n2 -- ☯) + +2018 20 18 20 23 0.5 +472 83 / -7 +100 + +100 * floor 100 / show_log + +[2 3] [swap truediv] infra + +dup infra key_bindings divmod + + 1 [dup 1 <<] make_generator 23 [x popd] times first + +mcc91 == [100 >] [10 -] [11 + mcc91 mcc91] ifte + == [100 >] [10 -] [11 + [mcc91] [mcc91] b] ifte + == [100 >] [10 -] [11 + [mcc91] dup b] ifte +mcc91 == [100 >] [10 -] [11 +] [dup b] genrec + +279841 20 20 20 202318 279841 279841 27984127984120202318 + +inscribe + +round_to_cents == 100 * ++ floor 100 / + + + [12 18] [[pm] infra] make_generator + + [12 18] [[[+] [3 /] fork popopdd] infra] make_generator + + [stack] [pop] while + + + diff --git a/joy/gui/default_joy_home/stack.pickle b/joy/gui/default_joy_home/stack.pickle new file mode 100644 index 0000000..4b4aaa9 --- /dev/null +++ b/joy/gui/default_joy_home/stack.pickle @@ -0,0 +1 @@ +(t. \ No newline at end of file diff --git a/joy/gui/default_joy_home/thun.config b/joy/gui/default_joy_home/thun.config new file mode 100644 index 0000000..b7403fc --- /dev/null +++ b/joy/gui/default_joy_home/thun.config @@ -0,0 +1,53 @@ + +[key bindings] + = swap + = dup + = roll< + = roll> + = over + = tuck + = parse + = words + = reset_log show_log + = clear reset_log show_log + = pop + = i + + +[Definitions] +of = swap at +product = 1 swap [*] step +flatten = [] swap [concat] step +quoted = [unit] dip +unquoted = [i] dip +enstacken = stack [clear] dip +? = dup truthy +disenstacken = ? [uncons ?] loop pop +dinfrirst = dip infra first +nullary = [stack] dinfrirst +unary = nullary popd +binary = nullary [popop] dip +ternary = unary [popop] dip +pam = [i] map +run = [] swap infra +sqr = dup mul +size = 0 swap [pop ++] step +fork = [i] app2 +cleave = fork [popd] dip +average = [sum 1.0 *] [size] cleave / +gcd = 1 [tuck modulus dup 0 >] loop pop +least_fraction = dup [gcd] infra [div] concat map +*fraction = [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons +*fraction0 = concat [[swap] dip * [*] dip] infra +down_to_zero = [0 >] [dup --] while +range_to_zero = unit [down_to_zero] infra +anamorphism = [pop []] swap [dip swons] genrec +range = [0 <=] [1 - dup] anamorphism +while = swap [nullary] cons dup dipd concat loop +dupdipd = dup dipd +primrec = [i] genrec +step_zero = 0 roll> step +codireco = cons dip rest cons +make_generator = [codireco] ccons +ifte = [nullary not] dipd branch + diff --git a/joy/gui/init_joy_home.py b/joy/gui/init_joy_home.py new file mode 100644 index 0000000..8c2f311 --- /dev/null +++ b/joy/gui/init_joy_home.py @@ -0,0 +1,124 @@ +''' +Utility module to help with setting up the initial contents of the +JOY_HOME directory. + +These contents are kept in this Python module as a base64-encoded zip +file, so you can just do, e.g.: + + import init_joy_home + init_joy_home.initialize(JOY_HOME) + +''' +import base64, os, StringIO, zipfile + + +def initialize(joy_home): + Z.extractall(joy_home) + + +def create_data(from_dir='./default_joy_home'): + f = StringIO.StringIO() + z = zipfile.ZipFile(f, mode='w') + for fn in os.listdir(from_dir): + from_fn = os.path.join(from_dir, fn) + z.write(from_fn, fn) + z.close() + return base64.encodestring(f.getvalue()) + + +Z = zipfile.ZipFile(StringIO.StringIO(base64.decodestring('''\ +UEsDBBQAAAAAAKW29EyLEfLTUQgAAFEIAAALAAAAc2NyYXRjaC50eHRyZXNldF9sb2cgd29yZHMg +bW91c2VfYmluZGluZ3Mga2V5X2JpbmRpbmdzCgpTdGFjayBDaGF0dGVyCgogZHVwIGR1cGQgZHVw +ZGQgb3ZlciB0dWNrCiBwb3AgcG9wZCBwb3BkZCBwb3BvcCBwb3BvcGQgcG9wb3BkZAogc3dhcCBy +b2xsPCByb2xsPiByb2xsZG93biByb2xsdXAgCiB1bml0IGNsZWFyCgpNYXRoCgogYWRkICsgc3Vi +IC0gbXVsICogdHJ1ZWRpdiAvIG1vZCAlCiBkaXYgZGl2bW9kIGZsb29yIHBtCiBhYnMgc3FyIHNx +cnQgbmVnIHBvdwogbWF4IG1pbiBzdW0gYXZlcmFnZSBwcm9kdWN0CiBwcmVkIC0tIHN1Y2MgKysg +bHNoaWZ0IDw8IHJzaGlmdCA+PgoKTG9naWMKCiBnZSBndCBlcSBsZSBsdCBuZQogIDwgPD0gPSAg +Pj0gPiAgIT0gPD4KIGFuZCAmIG9yIG5vdCB4b3IgXgogYm9vbCB0cnV0aHkgPwoKQ29tYmluYXRv +cnMKCiBpIHggYiBpbmZyYSBkaXAgZGlwZCBkaXBkZCBkdXBkaXAgZHVwZGlwZAogY2xlYXZlIGZv +cmsgYXBwMSBhcHAyIGFwcDMgbWFwIHBhbQogbnVsbGFyeSB1bmFyeSBiaW5hcnkgdGVybmFyeSAK +CkNvbnRyb2wgRmxvdwoKIGJyYW5jaCBjb25kIGlmdGUgY2hvaWNlCiBsb29wIHdoaWxlIGdlbnJl +YyBwcmltcmVjCiBtYWtlX2dlbmVyYXRvcgoKTGlzdCBNYW5pcHVsYXRpb24KCiBlbnN0YWNrZW4g +ZGlzZW5zdGFja2VuIHN0YWNrIHVuc3RhY2sKIGZpcnN0IGZpcnN0X3R3byBzZWNvbmQgdGhpcmQg +Zm91cnRoIHJlc3QgcnJlc3QKIGZsYXR0ZW4gZHJvcCB0YWtlIHJldmVyc2Ugc2VsZWN0IHppcAog +c2l6ZSBzb3J0IHNodW50IGdldGl0ZW0KIHN0ZXAgc3RlcF96ZXJvIHRpbWVzIAogY29ucyBjY29u +cyB1bmNvbnMgc3dvbnMgdW5zd29ucwogY29uY2F0IHVuaXF1ZQogcmVtb3ZlCiBhdCBvZiBwaWNr +CiB1bnF1b3RlZCBxdW90ZWQKCk1pc2MKCiBkb3duX3RvX3plcm8gY21wIGdjZCBoZWxwIGlkIAog +bGVhc3RfZnJhY3Rpb24gcGFyc2UgcXVvdGVkCiByYW5nZSByYW5nZV90b196ZXJvCiByZXNldF9s +b2cgIHNob3dfbG9nCiBydW4gCiBzdHVuY29ucyBzdHVudW5jb25zCiBzd2FhY2sgCiB2b2lkICAg +ICAKCgpbIF0gQWRkIGxvZ2dpbmc/ClsgXSBJTkkgZmlsZT8KWyBdIGRlZmluaXRpb25zLnR4dApb +IF0gSW50ZWdyYXRlIGluZmVyZW5jZQpbIF0gY29tbWFuZCB0byAocmUtKXJ1biB3aXRoIHRyYWNl +ClsgXSBCYWNrdGltZSBidXR0b24/CgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t +LS0tLS0tLS0tClsyMyAxOF0gICBbdW5pdCBpXQoKc3FyICBmb28gPT0gdW5jb25zIG11bAoKIHN3 +YWFjawoKIG92ZXIgW1tbbmVnXSBkdXBkaXAgc3FyIDRdIGRpcGQgKiAqIC0gc3FydCBwbV0gZGlw +IDIgKiBbL10gY29ucyBhcHAyCgo1IHNxcnQgMiAvIDAuNSArCjUgc3FydCAxICsgMiAvCnBoaSA9 +PSA1IHNxcnQgKysgMiAvCnBoaSA9PSAxLjYxODAzMzk4ODc0OTg5NQooQnV0IHRoaXMgaXMgTGFt +YmRhIEFic3RhY3Rpb24gc25lYWtpbmcgaW4gdGhlIGJhY2sgZG9vci4pCj0KY2xlYXIKCihuMSBu +MiAtLSDimK8pCgoyMDE4IDIwIDE4IDIwIDIzIDAuNQo0NzIgODMgLyAtNwoxMDAKCjEwMCAqIGZs +b29yIDEwMCAvICBzaG93X2xvZwoKWzIgM10gW3N3YXAgdHJ1ZWRpdl0gaW5mcmEKCmR1cCBpbmZy +YSBrZXlfYmluZGluZ3MgZGl2bW9kCgogIDEgW2R1cCAxIDw8XSBtYWtlX2dlbmVyYXRvciAgIDIz +IFt4IHBvcGRdIHRpbWVzIGZpcnN0CgptY2M5MSA9PSBbMTAwID5dIFsxMCAtXSBbMTEgKyBtY2M5 +MSBtY2M5MV0gaWZ0ZQogICAgICA9PSBbMTAwID5dIFsxMCAtXSBbMTEgKyBbbWNjOTFdIFttY2M5 +MV0gYl0gaWZ0ZQogICAgICA9PSBbMTAwID5dIFsxMCAtXSBbMTEgKyBbbWNjOTFdIGR1cCBiXSBp +ZnRlCm1jYzkxID09IFsxMDAgPl0gWzEwIC1dIFsxMSArXSBbZHVwIGJdIGdlbnJlYwoKMjc5ODQx +IDIwIDIwIDIwIDIwMjMxOCAyNzk4NDEgMjc5ODQxIDI3OTg0MTI3OTg0MTIwMjAyMzE4CgppbnNj +cmliZQoKcm91bmRfdG9fY2VudHMgPT0gMTAwICogKysgZmxvb3IgMTAwIC8KCgogICAgWzEyIDE4 +XSBbW3BtXSBpbmZyYV0gbWFrZV9nZW5lcmF0b3IKCiAgICBbMTIgMThdIFtbWytdIFszIC9dIGZv +cmsgcG9wb3BkZF0gaW5mcmFdIG1ha2VfZ2VuZXJhdG9yCgogICBbc3RhY2tdIFtwb3BdIHdoaWxl +CgoKClBLAwQUAAAAAABAQfVM5+RkR1EBAABRAQAABwAAAGxvZy50eHRKb3lweSAtIENvcHlyaWdo +dCDCqSAyMDE4IFNpbW9uIEZvcm1hbgpUaGlzIHByb2dyYW0gY29tZXMgd2l0aCBBQlNPTFVURUxZ +IE5PIFdBUlJBTlRZOyBmb3IgZGV0YWlscyByaWdodC1jbGljayAid2FycmFudHkiLiBUaGlzIGlz +IGZyZWUgc29mdHdhcmUsIGFuZCB5b3UgYXJlIHdlbGNvbWUgdG8gcmVkaXN0cmlidXRlIGl0IHVu +ZGVyIGNlcnRhaW4gY29uZGl0aW9uczsgcmlnaHQtY2xpY2sgInNoYXJpbmciIGZvciBkZXRhaWxz +LiBSaWdodC1jbGljayBvbiB0aGVzZSBjb21tYW5kcyB0byBzZWUgZG9jcyBvbiBVSSBjb21tYW5k +czoga2V5X2JpbmRpbmdzIG1vdXNlX2JpbmRpbmdzCgogPC0KUEsDBBQAAAAAAEFB9Ux3f5peAwAA +AAMAAAAMAAAAc3RhY2sucGlja2xlKHQuUEsDBBQAAAAAAHy09ExY7AlUJgUAACYFAAALAAAAdGh1 +bi5jb25maWcKW2tleSBiaW5kaW5nc10KPEY1PiA9IHN3YXAKPEY2PiA9IGR1cAo8U2hpZnQtRjU+ +ID0gcm9sbDwKPFNoaWZ0LUY2PiA9IHJvbGw+CjxGNz4gPSBvdmVyCjxTaGlmdC1GNz4gPSB0dWNr +CjxGOD4gPSBwYXJzZQo8RjEyPiA9IHdvcmRzCjxGMT4gPSByZXNldF9sb2cgc2hvd19sb2cKPEVz +Y2FwZT4gPSBjbGVhciByZXNldF9sb2cgc2hvd19sb2cKPENvbnRyb2wtRGVsZXRlPiA9IHBvcAo8 +Q29udHJvbC1pPiA9IGkKCgpbRGVmaW5pdGlvbnNdCm9mID0gc3dhcCBhdApwcm9kdWN0ID0gMSBz +d2FwIFsqXSBzdGVwCmZsYXR0ZW4gPSBbXSBzd2FwIFtjb25jYXRdIHN0ZXAKcXVvdGVkID0gW3Vu +aXRdIGRpcAp1bnF1b3RlZCA9IFtpXSBkaXAKZW5zdGFja2VuID0gc3RhY2sgW2NsZWFyXSBkaXAK +PyA9IGR1cCB0cnV0aHkKZGlzZW5zdGFja2VuID0gPyBbdW5jb25zID9dIGxvb3AgcG9wCmRpbmZy +aXJzdCA9IGRpcCBpbmZyYSBmaXJzdApudWxsYXJ5ID0gW3N0YWNrXSBkaW5mcmlyc3QKdW5hcnkg +PSBudWxsYXJ5IHBvcGQKYmluYXJ5ID0gbnVsbGFyeSBbcG9wb3BdIGRpcAp0ZXJuYXJ5ID0gdW5h +cnkgW3BvcG9wXSBkaXAKcGFtID0gW2ldIG1hcApydW4gPSBbXSBzd2FwIGluZnJhCnNxciA9IGR1 +cCBtdWwKc2l6ZSA9IDAgc3dhcCBbcG9wICsrXSBzdGVwCmZvcmsgPSBbaV0gYXBwMgpjbGVhdmUg +PSBmb3JrIFtwb3BkXSBkaXAKYXZlcmFnZSA9IFtzdW0gMS4wICpdIFtzaXplXSBjbGVhdmUgLwpn +Y2QgPSAxIFt0dWNrIG1vZHVsdXMgZHVwIDAgPl0gbG9vcCBwb3AKbGVhc3RfZnJhY3Rpb24gPSBk +dXAgW2djZF0gaW5mcmEgW2Rpdl0gY29uY2F0IG1hcAoqZnJhY3Rpb24gPSBbdW5jb25zXSBkaXAg +dW5jb25zIFtzd2FwXSBkaXAgY29uY2F0IFsqXSBpbmZyYSBbKl0gZGlwIGNvbnMKKmZyYWN0aW9u +MCA9IGNvbmNhdCBbW3N3YXBdIGRpcCAqIFsqXSBkaXBdIGluZnJhCmRvd25fdG9femVybyA9IFsw +ID5dIFtkdXAgLS1dIHdoaWxlCnJhbmdlX3RvX3plcm8gPSB1bml0IFtkb3duX3RvX3plcm9dIGlu +ZnJhCmFuYW1vcnBoaXNtID0gW3BvcCBbXV0gc3dhcCBbZGlwIHN3b25zXSBnZW5yZWMKcmFuZ2Ug +PSBbMCA8PV0gWzEgLSBkdXBdIGFuYW1vcnBoaXNtCndoaWxlID0gc3dhcCBbbnVsbGFyeV0gY29u +cyBkdXAgZGlwZCBjb25jYXQgbG9vcApkdXBkaXBkID0gZHVwIGRpcGQKcHJpbXJlYyA9IFtpXSBn +ZW5yZWMKc3RlcF96ZXJvID0gMCByb2xsPiBzdGVwCmNvZGlyZWNvID0gY29ucyBkaXAgcmVzdCBj +b25zCm1ha2VfZ2VuZXJhdG9yID0gW2NvZGlyZWNvXSBjY29ucwppZnRlID0gW251bGxhcnkgbm90 +XSBkaXBkIGJyYW5jaAoKUEsDBBQAAAAAAEK0k0yW6MvDbQMAAG0DAAAPAAAAZGVmaW5pdGlvbnMu +dHh0c2VlX3N0YWNrID09IGdvb2Rfdmlld2VyX2xvY2F0aW9uIG9wZW5fc3RhY2sKc2VlX3Jlc291 +cmNlcyA9PSBsaXN0X3Jlc291cmNlcyBnb29kX3ZpZXdlcl9sb2NhdGlvbiBvcGVuX3ZpZXdlcgpv +cGVuX3Jlc291cmNlX2F0X2dvb2RfbG9jYXRpb24gPT0gZ29vZF92aWV3ZXJfbG9jYXRpb24gb3Bl +bl9yZXNvdXJjZQpzZWVfbG9nID09ICJsb2cudHh0IiBvcGVuX3Jlc291cmNlX2F0X2dvb2RfbG9j +YXRpb24Kc2VlX2RlZmluaXRpb25zID09ICJkZWZpbml0aW9ucy50eHQiIG9wZW5fcmVzb3VyY2Vf +YXRfZ29vZF9sb2NhdGlvbgpyb3VuZF90b19jZW50cyA9PSAxMDAgKiArKyBmbG9vciAxMDAgLwpy +ZXNldF9sb2cgPT0gImRlbCBsb2cubGluZXNbMTpdIDsgbG9nLmF0X2xpbmUgPSAwIiBldmFsdWF0 +ZQpzZWVfbWVudSA9PSAibWVudS50eHQiIGdvb2Rfdmlld2VyX2xvY2F0aW9uIG9wZW5fcmVzb3Vy +Y2UKCiMgT3JkZXJlZCBCaW5hcnkgVHJlZSBkYXRhc3RydWN0dXJlIGZ1bmN0aW9ucy4KQlRyZWUt +bmV3ID09IHN3YXAgW1tdIFtdXSBjb25zIGNvbnMKIF9CVHJlZS1QID09IG92ZXIgW3BvcG9wIHBv +cG9wIGZpcnN0XSBudWxsYXJ5CiBfQlRyZWUtVD4gPT0gW2NvbnMgY29ucyBkaXBkZF0gY29ucyBj +b25zIGNvbnMgaW5mcmEKIF9CVHJlZS1UPCA9PSBbY29ucyBjb25zIGRpcGRdIGNvbnMgY29ucyBj +b25zIGluZnJhCiBfQlRyZWUtRSA9PSBwb3Agc3dhcCByb2xsPCByZXN0IHJlc3QgY29ucyBjb25z +CiBfQlRyZWUtcmVjdXIgPT0gX0JUcmVlLVAgW19CVHJlZS1UPl0gW19CVHJlZS1FXSBbX0JUcmVl +LVQ8XSBjbXAKQlRyZWUtYWRkID09IFtwb3BvcCBub3RdIFtbcG9wXSBkaXBkIEJUcmVlLW5ld10g +W10gW19CVHJlZS1yZWN1cl0gZ2VucmVjClBLAQIUAxQAAAAAAKW29EyLEfLTUQgAAFEIAAALAAAA +AAAAAAAAAACAgQAAAABzY3JhdGNoLnR4dFBLAQIUAxQAAAAAAEBB9Uzn5GRHUQEAAFEBAAAHAAAA +AAAAAAAAAACAgXoIAABsb2cudHh0UEsBAhQDFAAAAAAAQUH1THd/ml4DAAAAAwAAAAwAAAAAAAAA +AAAAAICB8AkAAHN0YWNrLnBpY2tsZVBLAQIUAxQAAAAAAHy09ExY7AlUJgUAACYFAAALAAAAAAAA +AAAAAAC0gR0KAAB0aHVuLmNvbmZpZ1BLAQIUAxQAAAAAAEK0k0yW6MvDbQMAAG0DAAAPAAAAAAAA +AAAAAAC0gWwPAABkZWZpbml0aW9ucy50eHRQSwUGAAAAAAUABQAeAQAABhMAAAAA'''))) + + +if __name__ == '__main__': + print create_data() diff --git a/joy/gui/main.py b/joy/gui/main.py index e6dde6c..51ab627 100755 --- a/joy/gui/main.py +++ b/joy/gui/main.py @@ -8,15 +8,16 @@ Joypy - Copyright © 2018 Simon Forman ' right-click "sharing" for details.' ' Right-click on these commands to see docs on UI commands: key_bindings mouse_bindings') import logging, os, pickle, sys +from textwrap import dedent +from ConfigParser import RawConfigParser + +from joy.gui.utils import init_home, argparser, FileFaker + +args = argparser.parse_args() +JOY_HOME = args.joy_home + _log = logging.getLogger(__name__) - -from textwrap import dedent - -from joy.gui.utils import init_home, FileFaker - -JOY_HOME, repo = init_home() - logging.basicConfig( format='%(asctime)-15s %(levelname)s %(name)s %(message)s', filename=os.path.join(JOY_HOME, 'thun.log'), @@ -24,12 +25,24 @@ logging.basicConfig( ) +repo = init_home(JOY_HOME) + + from joy.gui.textwidget import TextViewerWidget, tk, get_font, TEXT_BINDINGS from joy.gui.world import StackDisplayWorld from joy.library import initialize from joy.utils.stack import stack_to_string +cp = RawConfigParser() +cp.optionxform = str # Don't mess with uppercase. +with open(os.path.join(args.joy_home, 'thun.config')) as f: + cp.readfp(f) + + +GLOBAL_COMMANDS = dict(cp.items('key bindings')) + + tb = TEXT_BINDINGS.copy() tb.update({ '': lambda tv: tv.copy_selection_to_stack, @@ -40,21 +53,6 @@ tb.update({ defaults = dict(text_bindings=tb, width=80, height=25) -GLOBAL_COMMANDS = { - '': 'swap', - '': 'dup', - '': 'roll<', - '': 'roll>', - '': 'over', - '': 'tuck', - '': 'parse', - '': 'words', - '': 'reset_log show_log', - '': 'clear reset_log show_log', - '': 'pop', - } - - def repo_relative_path(path): return os.path.relpath( path, diff --git a/joy/gui/utils.py b/joy/gui/utils.py index e7b5a93..59c947e 100644 --- a/joy/gui/utils.py +++ b/joy/gui/utils.py @@ -1,35 +1,81 @@ -import os +import argparse, os, sys +from os import listdir, mkdir +from os.path import abspath, exists, expanduser, isfile, join from dulwich.errors import NotGitRepository from dulwich.repo import Repo -def init_home(): - ''' - Find and initialize the Joy home directory and repository. - ''' - JOY_HOME = os.environ.get('JOY_HOME') - if JOY_HOME is None: - JOY_HOME = os.path.expanduser('~/.joypy') - if not os.path.isabs(JOY_HOME): - JOY_HOME = os.path.abspath('./JOY_HOME') - #print 'JOY_HOME=' + JOY_HOME +COMMITTER = 'Joy ' +DEFAULT_JOY_HOME = '~/.joypy' - if not os.path.exists(JOY_HOME): - #print 'creating...' - os.makedirs(JOY_HOME, 0700) - #print 'initializing git repository...' - repo = Repo.init(JOY_HOME) - else: # path does exist - try: - repo = Repo(JOY_HOME) - except NotGitRepository: - #print 'initializing git repository...' - repo = Repo.init(JOY_HOME) - #else: - #print 'opened git repository.' - return JOY_HOME, repo +def home_dir(path): + '''Return the absolute path of an existing directory.''' + + fullpath = expanduser(path) if path.startswith('~') else abspath(path) + + if not exists(fullpath): + if path == DEFAULT_JOY_HOME: + print 'Creating JOY_HOME', repr(fullpath) + mkdir(fullpath, 0700) + else: + print >> sys.stderr, repr(fullpath), "doesn't exist." + raise ValueError(path) + + return fullpath + + +def init_home(fullpath): + ''' + Open or create the Repo. + If there are contents in the dir but it's not a git repo, quit. + ''' + try: + repo = Repo(fullpath) + except NotGitRepository: + print >> sys.stderr, repr(fullpath), "no repository" + + if listdir(fullpath): + print >> sys.stderr, repr(fullpath), "has contents\nQUIT." + sys.exit(2) + + print 'Initializing repository in', fullpath + repo = init_repo(fullpath) + + print 'Using repository in', fullpath + return repo + + +def init_repo(repo_dir): + ''' + Create a repo, load the initial content, and make the first commit. + Return the Repo object. + ''' + repo = Repo.init(repo_dir) + import joy.gui.init_joy_home + joy.gui.init_joy_home.initialize(repo_dir) + repo.stage([ + fn + for fn in listdir(repo_dir) + if isfile(join(repo_dir, fn)) + ]) + repo.do_commit('Initial commit.', committer=COMMITTER) + return repo + + +argparser = argparse.ArgumentParser( + description='Experimental Brutalist UI for Joy.', + ) + + +argparser.add_argument( + '-j', '--joy-home', + help='Use a directory other than %s as JOY_HOME' % DEFAULT_JOY_HOME, + default=DEFAULT_JOY_HOME, + dest='joy_home', + type=home_dir, + ) class FileFaker(object): diff --git a/joy/utils/types.py b/joy/utils/types.py index 9cfa573..7c0ce83 100644 --- a/joy/utils/types.py +++ b/joy/utils/types.py @@ -1,4 +1,22 @@ # -*- coding: utf_8 +# +# Copyright © 2018 Simon Forman +# +# This file is part of Thun +# +# Thun is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Thun is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Thun. If not see . +# from logging import getLogger, addLevelName _log = getLogger(__name__)