{"id":22813918,"url":"https://github.com/garlic0x1/rope","last_synced_at":"2025-04-05T21:47:08.076Z","repository":{"id":267067897,"uuid":"899823876","full_name":"garlic0x1/rope","owner":"garlic0x1","description":"Immutable Ropes for Common Lisp","archived":false,"fork":false,"pushed_at":"2024-12-23T00:23:38.000Z","size":300,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-23T01:23:40.584Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/garlic0x1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-07T05:32:36.000Z","updated_at":"2024-12-15T22:07:22.000Z","dependencies_parsed_at":"2024-12-23T01:23:16.097Z","dependency_job_id":"d3fe3ad0-630f-4a68-b49f-4c73a5afb8e0","html_url":"https://github.com/garlic0x1/rope","commit_stats":null,"previous_names":["garlic0x1/rope"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/garlic0x1%2Frope","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/garlic0x1%2Frope/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/garlic0x1%2Frope/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/garlic0x1%2Frope/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/garlic0x1","download_url":"https://codeload.github.com/garlic0x1/rope/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247406070,"owners_count":20933802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-12T13:01:05.129Z","updated_at":"2025-04-05T21:47:08.069Z","avatar_url":"https://github.com/garlic0x1.png","language":"Common Lisp","funding_links":[],"categories":["Recently Updated","Expert Systems"],"sub_categories":["[Dec 11, 2024](/content/2024/12/11/README.md)"],"readme":"Immutable Ropes for Common Lisp\n\nHave you ever wanted to make yet another Emacs clone?  Well now you\ncan use ropes to do it so you can tell everyone on Twitter and\nHackernews that your editor is blazingly fast and super serious and\nuses fancy text structures.\n\nNone of the exported symbols mutate ropes, they return new ones.  This\nlets us reuse as many leaves and branches as possible to reduce memory\nusage, as well as enable a functional style of programming.\n\n# Installation\n\nWith [Ultralisp](https://ultralisp.org/) installed:\n\n```lisp\n(ql:quickload :rope)\n```\n\n# Usage\n\nConvert a string to a rope with `make-rope`, and turn it back into a\nstring with `write-rope` passing `nil` as the output.\n\nYou can also pass an input stream or pathname to `make-rope` to\nefficiently read files.\n\n```lisp\n(let* ((rope (rope:make-rope \"Immutable Ropes for Common Lisp\"))\n       (super (rope:insert-rope rope 10 \"Super \"))\n       (superer (rope:kill-rope super 0 10)))\n  (list\n   (rope:write-rope rope nil)\n   (rope:write-rope super nil)\n   (rope:write-rope superer nil)))\n```\n\nSplit a rope at an index:\n\n```lisp\n(let ((rope (rope:make-rope \"Immutable Super Ropes for Common Lisp\")))\n  (multiple-value-bind (ante post) (rope:split-rope rope 16)\n    (list ante post)))\n```\n\nHere is what the split ropes look like graphed with `:cl-dot`.  I\ndecreased `rope::*long-leaf*` to 8 to better visualize such a small\nstring.\n\n![Split Rope](screenshots/split.png)\n\nConcatenate ropes together:\n\n```lisp\n(let ((rope-a (rope:make-rope \"Immutable Super Ropes\"))\n      (rope-b (rope:make-rope \" for Common Lisp\")))\n  (rope:concat-rope rope-a rope-b))\n```\n\n![Concatenated Rope](screenshots/concat.png)\n\nKill a segment of a rope:\n\n```lisp\n(let ((rope (rope:make-rope \"Immutable Ropes for Common Lisp\")))\n  (rope:write-rope (rope:kill-rope rope 20 27) t))\n```\n\nGet chars or strings at a position:\n\n```lisp\n(let ((rope (rope:make-rope \"Immutable Ropes for Common Lisp\")))\n  (print (rope:index-rope rope 2))\n  (print (rope:substr-rope rope 10 15)))\n```\n\n# Performance\n\nTime to insert is a good measure since it splits and concatenates.\nThis graph demonstrates O(log(n)) performance:\n\n![Insert Benchmark](screenshots/insert-benchmark.png)\n\nInserting into a gigabyte rope takes approximately 26 microseconds on\nmy i5-6200U.\n\n# Dev Utils\n\nIf you want to generate graphs as shown above, you will need to\ninstall `:cl-dot` (not in Quicklisp), and load `:rope/dev`.  Then you\ncan make a rope and run this:\n\n```lisp\n(defparameter rope::*long-leaf* 24)\n(defparameter rope::*short-leaf* 8)\n\n(let ((rope (rope::make-rope rope/dev::*string*)))\n  (multiple-value-bind (ante post) (rope::split-rope rope 30)\n    (rope/dev:graph-ropes (list rope ante post))))\n```\n\nIf you are using Sly in Emacs, it will automatically open up a PNG\nbuffer.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgarlic0x1%2Frope","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgarlic0x1%2Frope","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgarlic0x1%2Frope/lists"}