emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/latex-table-wizard 7137ca9641 01/70: First commit


From: ELPA Syncer
Subject: [elpa] externals/latex-table-wizard 7137ca9641 01/70: First commit
Date: Sat, 13 May 2023 08:59:09 -0400 (EDT)

branch: externals/latex-table-wizard
commit 7137ca9641955a8526eb497999e893791342f128
Author: Enrico Flor <nericoflor@gmail.com>
Commit: Enrico Flor <nericoflor@gmail.com>

    First commit
---
 .gitignore            |    1 +
 COPYING               |  674 +++++++++++++++++++++++++++
 latex-table-wizard.el | 1242 +++++++++++++++++++++++++++++++++++++++++++++++++
 move-01.gif           |  Bin 0 -> 180937 bytes
 readme.org            |  245 ++++++++++
 select-01.gif         |  Bin 0 -> 215650 bytes
 swap-01.gif           |  Bin 0 -> 359257 bytes
 7 files changed, 2162 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..c531d9867f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.elc
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000000..f288702d2f
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program 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.
+
+    This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/latex-table-wizard.el b/latex-table-wizard.el
new file mode 100644
index 0000000000..bbe2553c12
--- /dev/null
+++ b/latex-table-wizard.el
@@ -0,0 +1,1242 @@
+;;; latex-table-wizard.el --- Magic editing of LaTeX tables  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Enrico Flor
+
+;; Author: Enrico Flor <enrico@eflor.net>
+;; Maintainer: Enrico Flor <enrico@eflor.net>
+;; URL: https://github.com/enricoflor/latex-table-wizard
+;; Version: 0.0.1
+
+;; Package-Requires: ((emacs "27.1") (auctex "12.1") (transient "0.3.7"))
+
+;; SPDX-License-Identifier: GPL-3.0-or-later
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides you with commands to smartly navigate and
+;; edit LaTeX table-like environments with a transient.el-based
+;; interface.  Table-like environments are portions of text delimited
+;; by a pair of matching "\begin" and "\end" macros that organize
+;; output text into aligned colums.
+
+;; With this package you can navigate and edit these tables easily
+;; even if the source text is not aligned, because you will have
+;; movement commands that specfically target cells in the four
+;; directions of motion.
+
+;; By default, the syntax this package expects is the one of standards
+;; LaTeX tabular environments, whereby "&" separates columns and "\\"
+;; separates rows.  Additional, or different, separators can be added
+;; by appending the correct regexp strings to the variable
+;; latex-table-wizard-column-delimiters and
+;; latex-table-wizard-row-delimiters.
+
+;; This package tries to be smart and not be fooled by the presence of
+;; embedded environments and embedded tables (that is, a table inside
+;; of the cell of a table).
+
+;;; Code:
+
+;;; Dependencies
+
+(require 'cl-lib)
+(require 'rx)
+(require 'regexp-opt)
+(eval-when-compile (require 'subr-x))
+(require 'transient)
+
+;;; Regular expressions
+
+;; (defconst latex-table-wizard--macro-prefix-re
+;;   (rx (seq (zero-or-one (or (not 92) (seq 92 92))) "\\"))
+;;   "Regexp matching unescaped \"\\\".")
+
+(defconst latex-table-wizard--macro-args-re
+  (rx (seq (zero-or-more                    ; obligatory arguments
+            (seq "{" (*? anything) "}"))
+           (zero-or-more                    ; optional arguments
+            (seq "[" (*? anything) "]" ))
+           (zero-or-more                    ; obligatory arguments
+            (seq "{" (*? anything) "}"))))
+  "Regexp matching argument part of LaTeX macros.")
+
+(defconst latex-table-wizard--macro-re
+  (concat "\\\\"
+          ;; latex-table-wizard--macro-prefix-re
+          (rx (group-n 1 (one-or-more alnum)))
+          latex-table-wizard--macro-args-re)
+  "Regexp matching unescaped LaTeX macros.
+
+Capture group 1 matches the name of the macro.")
+
+(defconst latex-table-wizard-column-delimiters '("[^\\\\]&")
+  "List of regexps matching column delimiters.")
+
+(defconst latex-table-wizard-row-delimiters '("\\\\\\\\")
+  "List of regexps matching row delimiters.")
+
+(defvar latex-table-wizard-hline-macros '("cline"
+                                          "vline"
+                                          "midrule"
+                                          "hline"
+                                          "toprule"
+                                          "bottomrule")
+  "Name of macros that draw horizontal lines.
+
+Each member of this list is a string that would be between the
+\"\\\" and the arguments.")
+
+
+;; Every time latex-table-wizard--parse-table is evaluated, the values
+;; of the variables below is set:
+(defvar latex-table-wizard--current-col-delims nil)
+(defvar latex-table-wizard--current-row-delims nil)
+(defvar latex-table-wizard--current-hline-macros nil)
+
+(defvar latex-table-wizard-new-environments-alist nil
+  "Alist mapping environment names to property lists.
+
+The environment name is a string, for example \"foo\" for an
+environment like
+
+  \\begin{foo}
+      ...
+  \\end{foo}
+
+The cdr of each mapping is a property list with three keys:
+
+   :col
+   :row
+   :lines
+
+The values for :col and :row are two lists of regexps.
+
+The value for :lines is a list of strings just like is the case
+for `latex-table-wizard-hline-macros'.")
+
+(defsubst latex-table-wizard--set-current-values ()
+  "Set temporary values that specify the syntax of the environment.
+
+If the current environment is one that is mapped to something in
+`latex-table-wizard-new-environments', set the values accordingly."
+  (if-let ((vals (cdr (assoc (LaTeX-current-environment)
+                             latex-table-wizard-new-environments-alist))))
+      (setq latex-table-wizard--current-col-delims
+            (plist-get (cdr (assoc (LaTeX-current-environment)
+                                   latex-table-wizard-new-environments-alist))
+                       :col)
+
+            latex-table-wizard--current-row-delims
+            (plist-get (cdr (assoc (LaTeX-current-environment)
+                                   latex-table-wizard-new-environments-alist))
+                       :row)
+
+            latex-table-wizard--current-hline-macros
+            (plist-get (cdr (assoc (LaTeX-current-environment)
+                                   latex-table-wizard-new-environments-alist))
+                       :lines))
+    (setq latex-table-wizard--current-col-delims
+          latex-table-wizard-column-delimiters
+
+          latex-table-wizard--current-row-delims
+          latex-table-wizard-row-delimiters
+
+          latex-table-wizard--current-hline-macros
+          latex-table-wizard-hline-macros)))
+
+
+
+;;; Parsing
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; The central data structure is the CELL, which is a plist with     ;;
+;; four keys:                                                        ;;
+;;                                                                   ;;
+;; + :column (column number, starting from 0 as the leftmost column) ;;
+;; + :row (row number, starting from 0 as the top row)               ;;
+;; + :start (marker, beginning of inside of the cell)                ;;
+;; + :end (marker, end of inside of the cell)                        ;;
+;;                                                                   ;;
+;; A parse of a table is a list of all its cells represented as such ;;
+;; plists.                                                           ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defsubst latex-table-wizard--end-of-macro (&optional name)
+  "If looking at unescaped macro named NAME, go to its end.
+
+If NAME is nil, skip any LaTeX macro that point is looking at."
+  (let* ((n (or name (rx (one-or-more alnum))))
+         (macro-re (concat "\\\\" n latex-table-wizard--macro-args-re)))
+    (unless (looking-back "[^\\\\]\\\\")
+      (when (looking-at macro-re)
+        (match-end 0)))))
+
+(defsubst latex-table-wizard--get-cell-boundaries (col-re
+                                                   row-re
+                                                   &optional limit)
+  "Return boundaries of current cell (where point is).
+
+What is returned is a list of the form
+
+    (B E EOR)
+
+where B and E are markers (beginning and end of the cell), and
+EOR is t iff this cell is the rightmost cell in the current row,
+nil otherwise.
+
+COL-RE and ROW-RE are regular expressions matching column and row
+delimiters respectively.
+
+LIMIT is a buffer position at which the parsing stops, and
+defaults to `point-max' if nothing else is passed as the
+argument."
+  (let ((lim (or limit (point-max)))
+        (beg (point-marker))
+        (end)
+        (end-of-row))
+    (while (and (< (point) lim) (not end))
+      (cond ((and (looking-at "%")
+                  (not (looking-back "[^\\\\]\\\\")))
+             ;; the first step is important to avoid being fooled by
+             ;; column or row delimiters in comments!
+             (forward-line))
+            ((looking-at "[[:space:]]*\\\\begin{[[:alnum:]]+}")
+             (skip-syntax-forward " ")
+             (forward-char 1)
+             (LaTeX-find-matching-end))
+            ((looking-at (concat "[[:space:]]*" latex-table-wizard--macro-re))
+             (goto-char (match-end 0)))
+            ((looking-at col-re)
+             ;; a column delimiter: bingo
+             (goto-char (match-beginning 0))
+             (setq end (point-marker))
+             (goto-char (match-end 0)))
+            ((looking-at row-re)
+             ;; a row delimiter: bingo
+             (let ((end-of-previous-cell
+                    (progn (goto-char (1- (match-beginning 0)))
+                           (point-marker))))
+               (goto-char (match-end 0))
+               (setq end end-of-previous-cell
+                     end-of-row t)
+               (latex-table-wizard--skip-stuff lim)))
+            (t
+             ;; nothing special, just go one step forward
+             (forward-char 1))))
+    `(,beg ,end ,end-of-row)))
+
+(defsubst latex-table-wizard--get-env-ends (table)
+  "Given TABLE, return beginning and end of the environemnt.
+
+TABLE is a list of cell plists.  The return type is a cons
+cell (B . E) with B and E being markers."
+  (cons (apply #'min (mapcar (lambda (x) (plist-get x :start)) table))
+        (apply #'max (mapcar (lambda (x) (plist-get x :end)) table))))
+
+(defvar-local latex-table-wizard--parsed-table-delims nil)
+
+(defsubst latex-table-wizard--disjoin (str-list &optional sep)
+  "Concatenate strings in STR-LIST with separtor SEP.
+
+If SEP is nil, the separator used is \"\\\\|\""
+  (let ((separator (or sep "\\|")))
+    (mapconcat #'identity str-list separator)))
+
+(defsubst latex-table-wizard--skip-stuff (limit)
+  "Skip comments, blank space and hline macros.
+
+Hline macros are LaTeX macros whose name is a string in
+`latex-table-wizard--current-hline-macros'.
+
+Stop the skipping at LIMIT (a buffer position or a marker)."
+  (let ((done)
+        (new-start-of-line))
+    (catch 'stop
+      (while (and (not done) (<= (point) limit))
+        (skip-syntax-forward " ")
+        (let ((temp-pos (point)))
+          (when (looking-at "\n\\|%")
+            (forward-line)
+            (setq new-start-of-line (point))
+            (when (looking-at (concat
+                               "[[:space:]]*"
+                               (latex-table-wizard--disjoin
+                                latex-table-wizard--current-col-delims)))
+              (throw 'stop nil)))
+          (ignore-errors
+            (goto-char (latex-table-wizard--end-of-macro
+                        (concat
+                         (regexp-opt
+                          latex-table-wizard--current-hline-macros)
+                         latex-table-wizard--macro-args-re))))
+          (when (looking-at "\n\\|%")
+            (forward-line)
+            (setq new-start-of-line (point)))
+          (when (eq (point) temp-pos)
+            ;; we haven't moved since trying to skip whitespace, we are
+            ;; done here.
+            (setq done t)))))
+    (when new-start-of-line (goto-char new-start-of-line))))
+
+;; (defsubst latex-table-wizard--contentless-string-p (beg end)
+;;   (let ((str (buffer-substring-no-properties beg end))
+;;         (hline-macros (concat "[^\\\\]\\\\"
+;;                               (regexp-opt
+;;                                latex-table-wizard--current-hline-macros)
+;;                               latex-table-wizard--macro-args-re)))
+;;     (thread-last
+;;       str
+;;       (replace-regexp-in-string "[^\\\\]%.*$" "")
+;;       (replace-regexp-in-string hline-macros "")
+;;       (string-blank-p))))
+
+(defun latex-table-wizard--parse-table ()
+  "Parse table(-like) environment point is in.
+
+Return a list of plists, each of which is a cells and has the
+form
+
+    (:column C :row R :start S :end E).
+
+Each value is an integer, S and E are markers."
+  (let* ((cells-list '())
+         (col 0)
+         (row 0)
+         (env-beg (save-excursion
+                    (LaTeX-find-matching-begin)
+                    (goto-char (latex-table-wizard--end-of-macro))
+                    (point-marker)))
+         (env-end (save-excursion
+                    (LaTeX-find-matching-end)
+                    (re-search-backward (concat
+                                         "\\\\"
+                                         (rx (one-or-more alnum))
+                                         latex-table-wizard--macro-args-re)
+                                        nil t)
+                    (forward-char -1)
+                    (point-marker)))
+         (done))
+    (latex-table-wizard--set-current-values)
+    (save-excursion
+      (goto-char env-beg)
+      (while (< (point) env-end)
+        ;; (latex-table-wizard--skip-stuff env-end)
+        (when (looking-at-p "[[:space:]]*\\($\\|%\\)")
+          ;; nothing interesting left between point and eol
+          (forward-line))
+        (let* ((col-re
+                (latex-table-wizard--disjoin
+                 latex-table-wizard--current-col-delims))
+               (row-re (latex-table-wizard--disjoin
+                        latex-table-wizard--current-row-delims))
+               (hline-macro-re (concat
+                                (regexp-opt
+                                 latex-table-wizard--current-hline-macros)
+                                latex-table-wizard--macro-args-re))
+               (data (latex-table-wizard--get-cell-boundaries
+                      col-re row-re env-end)))
+          (push `( :column ,col
+                   :row ,row
+                   :start ,(nth 0 data)
+                   :end ,(if (nth 1 data) (nth 1 data) env-end))
+                cells-list)
+          (if (nth 2 data)              ; this was the last cell in the row
+              (setq row (1+ row)
+                    col 0)
+            (setq col (1+ col)))
+          ;; if we just hit the end of a row and the next thing coming
+          ;; is another row delimiter, skip that one (because you are
+          ;; not in a cell)
+          (while (and (nth 2 data)
+                      (save-excursion
+                        (skip-syntax-forward " ")
+                        (looking-at-p row-re)))
+            (re-search-forward row-re nil t)))))
+    (setq latex-table-wizard--parsed-table-delims
+          (latex-table-wizard--get-env-ends cells-list))
+    cells-list))
+
+(defsubst latex-table-wizard--get-cell-pos (column row table)
+  "Return the cell plist from TABLE at (COLUMN, ROW) position."
+  (car (cl-remove-if-not
+        (lambda (x) (and (eq column (plist-get x :column))
+                         (eq row (plist-get x :row))))
+        table)))
+
+(defsubst latex-table-wizard--sort (dir x y)
+  "Return t if cell X precedes Y.
+
+Precedence depends on the value of DIR (either 'next',
+'previous', 'forward' or 'backward')."
+  (let ((rows (list (plist-get x :row) (plist-get y :row)))
+        (cols (list (plist-get x :column) (plist-get y :column))))
+    (if (or (eq dir 'next) (eq dir 'previous))
+        (if (apply #'eq cols)
+            (apply #'< rows)
+          (apply #'< cols))
+      (if (apply #'eq rows)
+          (apply #'< cols)
+        (apply #'< rows)))))
+
+(defsubst latex-table-wizard--get-extreme (dir table current-cell)
+  "Return the last cell in a certain row or cell from TABLE.
+
+The goal is to get to the last cell in the same row or same
+column as CURRENT-CELL.
+
+Whether to look for the last column or row depends on the value
+of DIR (either 'next', 'previous', 'forward' or 'backward')."
+  (let* ((prop (if (or (eq dir 'backward) (eq dir 'forward)) :column :row))
+         (curr-prop (if (eq prop :column) :row :column))
+         (curr-value (plist-get current-cell curr-prop))
+         (res (if (or (eq dir 'backward) (eq dir 'previous))
+                  0
+                (thread-last
+                  table
+                  (cl-remove-if-not
+                   (lambda (x) (eq (plist-get x curr-prop) curr-value)))
+                  (mapcar (lambda (x) (plist-get x prop)))
+                  (apply 'max)))))
+    (thread-last table
+                 (cl-remove-if-not
+                  (lambda (x) (and (eq (plist-get x curr-prop) curr-value)
+                                   (eq (plist-get x prop) res))))
+                 (car))))
+
+(defsubst latex-table-wizard--point-on-regexp-p (regexp
+                                                 &optional capture-group
+                                                 search-beginning-pos)
+  "Return non-nil if point is on a substring matched by REGEXP.
+
+If CAPTURE-GROUP is non-nil, limit the condition to the substring
+matched by the corresponding capture group.  If CAPTURE-GROUP is
+nil, it defaults to 0.
+
+What is returned is a list of the form
+
+    (S B E)
+
+where S is the substring matched, and B and E are the buffer
+position corresponding to the beginning and the end of such
+substring.
+
+Start the search from SEARCH-BEGINNING-POS (a buffer position or
+marker): if this argument is nil, start the search from the
+beginning of the available portion of the buffer."
+  (let ((position (point))
+        (group (or capture-group 0))
+        (search-b (or search-beginning-pos (point-min))))
+    (save-match-data
+      (save-excursion
+        (goto-char search-b)
+        (catch 'found
+          (while (re-search-forward regexp nil t)
+            (when (<= (match-beginning group) position (match-end group))
+              (throw 'found (list (match-string-no-properties group)
+                                  (match-beginning group)
+                                  (match-end group))))
+            nil))))))
+
+
+
+;;; Moving around
+
+(defun latex-table-wizard--get-other-cell (dir same-line count table curr)
+  "Return cell plist from TABLE.
+
+The cell that is returned is the one found moving COUNT cells
+from current cell CURR in direction DIR (either 'forward',
+'backward', 'next' or 'previous').
+
+If SAME-LINE is non-nil, loop over the current row (if DIR is
+'forward' or 'backward'), or column (if DIR is 'next' or
+'previous').  Otherwise continue search for cell in a different
+row or column if no cell is left in the current DIR."
+  (let* ((sorted (if same-line
+                     (let* ((prop (if (or (eq dir 'forward)
+                                          (eq dir 'backward))
+                                      :row
+                                    :column))
+                            (other-prop (if (eq prop :row) :column :row)))
+                       (sort (cl-remove-if-not
+                              (lambda (x) (eq (plist-get x prop)
+                                              (plist-get curr prop)))
+                              table)
+                             (lambda (x y) (< (plist-get x other-prop)
+                                              (plist-get y other-prop)))))
+                   (sort table
+                         (lambda (x y)
+                           (latex-table-wizard--sort dir x y)))))
+         (cell-num (length sorted))
+         (now (cl-position curr sorted :test 'equal))
+         (new-index (if (or (eq dir 'next)
+                            (eq dir 'forward))
+                        (+ now count)
+                      (- now count))))
+    (cond ((and (>= new-index 0)
+                (> cell-num new-index))
+           ;; we are staying inside of the list
+           (nth new-index sorted))
+          ((<= cell-num new-index)
+           ;; we have to start from the top left corner of the table
+           (nth (1- (- new-index cell-num)) sorted))
+          ((< new-index 0)
+           ;; we have to start from the bottom right corner of the table
+           (nth (- cell-num (abs new-index)) sorted))
+          (t nil))))
+
+
+(defsubst latex-table-wizard--remove-overlays (&optional table beg end)
+  "Remove table internal overlays generated by latex-table-wizard.
+
+These are the overlays that have a non-nil value for the name
+property 'table-inside-ol'.
+
+Optional arguments BEG and END are passed, they are buffer
+positions or markers indicating beginning and end of the table.
+
+Optional arguments TABLE is a list of cell plists: if its not
+given, a value is retrieved with
+`latex-table-wizard--parse-table'."
+  (if beg
+      (remove-overlays beg end 'tabl-inside-ol t)
+    (let* ((tab (or table (latex-table-wizard--parse-table)))
+           (lims (latex-table-wizard--get-env-ends tab)))
+      (remove-overlays (car lims) (cdr lims) 'tabl-inside-ol t))))
+
+(defsubst latex-table-wizard--hl-cells (list-of-cells)
+  "Highlight cells in LIST-OF-CELLS with an overlay.
+
+The overlay has a non-nil value for the name property
+'table-inside-ol'."
+  (let ((ols '()))
+    (dolist (x list-of-cells)
+      (push (make-overlay (plist-get x :start)
+                          (plist-get x :end))
+            ols))
+    (dolist (x ols)
+      (overlay-put x 'tabl-inside-ol t)
+      (overlay-put x 'face
+                   `((t (:background ,(face-attribute 'region
+                                                      :background))))))))
+
+(defun latex-table-wizard--jump (dir &optional absolute count same-line)
+  "Move point to the beginning of a cell in the table.
+
+DIR is either 'next', 'previous', 'forward' or 'backward' and
+determines the direction of motion.  This function assumes being
+evaluated with point inside of a tabular-like environment.
+
+With ABSOLUTE being t, move to the last or first cell in the row
+or column (depending on the value of DIR) point is currently in.
+
+COUNT is a positive integer that determines how many steps in
+direction DIR to take.
+
+If SAME-LINE is non-nil, never leave current column or row."
+  (unless (ignore-errors (save-excursion (LaTeX-find-matching-begin)))
+    (user-error "Not in a LaTeX environment"))
+  (when-let ((macro-at-point
+              (latex-table-wizard--point-on-regexp-p
+               latex-table-wizard--macro-re
+               0 (line-beginning-position))))
+    (cond ((string-prefix-p "\\begin" (nth 0 macro-at-point))
+           (goto-char (nth 1 macro-at-point)))
+          ((string-prefix-p "\\end" (nth 0 macro-at-point))
+           (goto-char (nth 2 macro-at-point)))))
+  (let* ((cells (latex-table-wizard--parse-table))
+         (curr (latex-table-wizard--get-thing 'cell cells))
+         (target (if absolute
+                     (latex-table-wizard--get-extreme dir cells curr)
+                   (latex-table-wizard--get-other-cell
+                    dir same-line count cells curr))))
+    (latex-table-wizard--remove-overlays cells)
+    (goto-char (plist-get target :start))
+    (latex-table-wizard--hl-cells (list target))
+    (latex-table-wizard--hl-cells latex-table-wizard--selection)))
+
+(defsubst latex-table-wizard--locate-point (pos table)
+  "Return cell from TABLE in which position POS is in.
+
+POS is a buffer position or a marker."
+  (let ((candidate (car (cl-remove-if-not
+                         (lambda (x) (<= (plist-get x :start)
+                                         pos
+                                         (plist-get x :end)))
+                         table)))
+        (ends (latex-table-wizard--get-env-ends table)))
+    (cond (candidate
+           candidate)
+          ((< pos (car ends))
+           (latex-table-wizard--get-cell-pos 0 0 table))
+          ((> pos (cdr ends))
+           (car (cl-remove-if-not
+                 (lambda (x) (eq (plist-get x :end) (cdr ends)))
+                 table)))
+          (t (goto-char (apply #'max
+                               (mapcar (lambda (x) (plist-get x :start))
+                                       (cl-remove-if-not
+                                        (lambda (x) (< (plist-get x :end) pos))
+                                        table))))))))
+
+(defsubst latex-table-wizard--get-thing (thing &optional table)
+  "Return THING point is in.
+
+THING can be either 'cell', 'column' or 'row.
+
+TABLE is a list of cell plists.  If it is nil, evaluate
+`latex-table-wizard--parse-table' to get a value.
+
+If THING is 'cell', return one plist, else return a list of
+plists."
+  (let* ((pos (point))
+         (cells-list (or table (latex-table-wizard--parse-table)))
+         (curr (latex-table-wizard--locate-point pos cells-list)))
+    (if (eq thing 'cell)
+        curr
+      (let* ((prop (if (eq thing 'row) :row :column))
+             (other-prop (if (eq thing 'row) :column :row))
+             (curr-value (plist-get curr prop)))
+        (sort (cl-remove-if-not (lambda (x) (eq curr-value (plist-get x prop)))
+                                cells-list)
+              (lambda (x y) (> (plist-get x other-prop)
+                               (plist-get x other-prop))))))))
+
+
+
+;;; Swapping functions
+
+(defsubst latex-table-wizard--swap-substrings (x y)
+  "Swap two buffer substrings.
+
+X and Y are each a list of the form '(B E)', where B and E are
+markers corresponding to the beginning and the end of the buffer
+substring."
+  (save-excursion
+    (let ((x-string (concat " "
+                            (string-trim
+                             (apply #'buffer-substring x))
+                            " "))
+          (y-string (concat " "
+                            (string-trim
+                             (apply #'buffer-substring y))
+                            " ")))
+      (goto-char (nth 1 x))
+      (apply #'delete-region x)
+      (insert y-string)
+      (just-one-space)
+      (goto-char (nth 1 y))
+      (apply #'delete-region y)
+      (insert x-string)
+      (just-one-space))))
+
+(defsubst latex-table-wizard--swap-cells (x y)
+  "Evaluate `latex-table-wizard--swap-substrings' on cells X and Y."
+  (latex-table-wizard--swap-substrings (list (plist-get x :start)
+                                             (plist-get x :end))
+                                       (list (plist-get y :start)
+                                             (plist-get y :end))))
+
+(defsubst latex-table-wizard--get-this-value-prop (line prop value)
+  "Return the cell from list LINE that has VALUE for property PROP."
+  (car (cl-remove-if-not (lambda (x) (eq value (plist-get x prop))) line)))
+
+(defsubst latex-table-wizard--type-of-selection (sel)
+  "Return type of list of cells SEL.
+
+Non-nil values that are returned are is either 'cell' (if SEL
+only contains one cell), 'column' or 'row'.
+
+If SEL is a list of more than one cell such that not all the
+cells have the same value for either :column or :row, it means
+that this selection is neither a column or a row, and nil is
+returned."
+  (cond ((eq 1 (length sel))
+         'cell)
+        ((thread-last sel
+                      (mapcar (lambda (x) (plist-get x :column)))
+                      (delete-dups)
+                      (length)
+                      (eq 1))
+         'column)
+        ((thread-last sel
+                      (mapcar (lambda (x) (plist-get x :row)))
+                      (delete-dups)
+                      (length)
+                      (eq 1))
+         'row)
+        (t nil)))
+
+(defun latex-table-wizard--swap-line (type line1 line2)
+  "Swap columns or rows LINE1 and LINE2.
+
+TYPE is either 'column' or 'row'."
+  (save-excursion
+    (let ((prop (if (eq type 'column) :row :column)))
+      (dolist (x line1)
+        (let ((other (latex-table-wizard--get-this-value-prop
+                      line2 prop (plist-get x prop))))
+          (latex-table-wizard--swap-cells x other))))))
+
+
+
+;; Swap columns and rows
+
+(defun latex-table-wizard--swap-adjacent-line (dir type)
+  "Swap current thing of type TYPE with the one in direction DIR.
+
+DIR is either 'forward', 'backward', 'next' or 'previous'.
+
+TYPE is either 'cell', 'column' or 'row'."
+  (let* ((table (latex-table-wizard--parse-table))
+         (current-cell (latex-table-wizard--get-thing 'cell table))
+
+         (other-cell (latex-table-wizard--get-other-cell
+                      dir t 1 table current-cell)))
+    (if (eq type 'cell)
+        (latex-table-wizard--swap-cells current-cell other-cell)
+      (let* ((current (latex-table-wizard--get-thing type table))
+             (other (cl-loop for x in current
+                             collect
+                             (latex-table-wizard--get-other-cell
+                              dir t 1 table x))))
+        (latex-table-wizard--swap-line type current other)))
+    (let ((new-table (latex-table-wizard--parse-table)))
+      (goto-char (plist-get (latex-table-wizard--get-cell-pos
+                             (plist-get other-cell :column)
+                             (plist-get other-cell :row)
+                             new-table)
+                            :start))
+      (latex-table-wizard--remove-overlays new-table)
+      (if (eq type 'cell)
+          (latex-table-wizard--hl-cells
+           (list (latex-table-wizard--get-thing type new-table)))
+        (latex-table-wizard--hl-cells
+         (latex-table-wizard--get-thing type new-table))))))
+
+(defvar latex-table-wizard--selection nil
+  "Current selection, a list of cell objects.")
+
+(defun latex-table-wizard--select-thing (thing)
+  "Add THING point is at to list `latex-table-wizard--selection'.
+
+THING is either 'cell', 'column' or 'row'."
+  (let* ((table (latex-table-wizard--parse-table))
+         (sel (latex-table-wizard--get-thing thing table)))
+    (if (eq thing 'cell)
+        (setq latex-table-wizard--selection
+              (cons sel latex-table-wizard--selection))
+      (setq latex-table-wizard--selection sel))
+    (message (format "%s selected for swapping"
+                     (cond ((eq thing 'cell)
+                            (format "Cell (%s,%s)"
+                                    (plist-get sel :column)
+                                    (plist-get sel :row)))
+                           ((eq thing 'row)
+                            (format "Row %s"
+                                    (plist-get (car sel) :row)))
+                           (t
+                            (format "Column %s"
+                                    (plist-get (car sel) :column))))))
+    (if (eq thing 'cell)
+        (latex-table-wizard--hl-cells (list sel))
+      (latex-table-wizard--hl-cells sel))))
+
+
+
+;;; Interactive functions
+
+;;;###autoload
+(defun latex-table-wizard-right (&optional n)
+  "Move point N cells to the right.
+
+Leave point at the beginning of the cell.
+
+If N is nil, move one cell to the right.
+
+If there is no cell to the right of where point is, move to the
+leftmost cell of the row below where point is."
+  (interactive "p")
+  (latex-table-wizard--jump 'forward nil n))
+
+;;;###autoload
+(defun latex-table-wizard-left (&optional n)
+  "Move point N cells to the left.
+
+Leave point at the beginning of the cell.
+
+If N is nil, move one cell to the left.
+
+If there is no cell to the left of where point is, move to the
+rightmost cell of the row above where point is."
+  (interactive "p")
+  (latex-table-wizard--jump 'backward nil n))
+
+;;;###autoload
+(defun latex-table-wizard-down (&optional n)
+  "Move point N cells down.
+
+Leave point at the beginning of the cell.
+
+If N is nil, move one row down.
+
+If there is no row below where point is, move to the top cell of
+the column to the right of where point is."
+  (interactive "p")
+  (latex-table-wizard--jump 'next nil n))
+
+;;;###autoload
+(defun latex-table-wizard-up (&optional n)
+  "Move point N cells up.
+
+Leave point at the beginning of the cell.
+
+If N is nil, move one row up.
+
+If there is no row above where point is, move to the bottom cell
+of the column to the left of where point is."
+  (interactive "p")
+  (latex-table-wizard--jump 'previous nil n))
+
+;;;###autoload
+(defun latex-table-wizard-end-of-row ()
+  "Move point to the rightmost cell in current row."
+  (interactive)
+  (latex-table-wizard--jump 'forward t))
+
+;;;###autoload
+(defun latex-table-wizard-beginning-of-row ()
+  "Move point to the leftmost cell in current row."
+  (interactive)
+  (latex-table-wizard--jump 'backward t))
+
+;;;###autoload
+(defun latex-table-wizard-bottom ()
+  "Move point to the bottom cell in current column."
+  (interactive)
+  (latex-table-wizard--jump 'next t))
+
+;;;###autoload
+(defun latex-table-wizard-top ()
+  "Move point to the top cell in current column."
+  (interactive)
+  (latex-table-wizard--jump 'previous t))
+
+;;;###autoload
+(defun latex-table-wizard-end-of-cell ()
+  "Move point to the end of the current cell."
+  (interactive)
+  (let ((cell (latex-table-wizard--get-thing 'cell)))
+    (goto-char (plist-get cell :end))))
+
+;;;###autoload
+(defun latex-table-wizard-beginning-of-cell ()
+  "Move point to the beginning of the current cell."
+  (interactive)
+  (let ((cell (latex-table-wizard--get-thing 'cell)))
+    (goto-char (plist-get cell :start))))
+
+;;;###autoload
+(defun latex-table-wizard-mark-cell ()
+  "Mark current cell.
+
+TABLE is a list of cell plists.  If it is nil, evaluate
+`latex-table-wizard--parse-table' to get a value."
+  (interactive)
+  (let* ((cells-list (or table (latex-table-wizard--parse-table)))
+         (cell (latex-table-wizard--get-thing 'cell cells-list)))
+    (push-mark (plist-get cell :start) nil t)
+    (goto-char (plist-get cell :end))))
+
+;;;###autoload
+(defun latex-table-wizard-swap-column-right ()
+  "Swap current column and the one to the right."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'forward 'column))
+
+;;;###autoload
+(defun latex-table-wizard-swap-column-left ()
+  "Swap current column and the one to the left."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'backward 'column))
+
+;;;###autoload
+(defun latex-table-wizard-swap-row-up ()
+  "Swap current row and the one above."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'previous 'row))
+
+;;;###autoload
+(defun latex-table-wizard-swap-row-down ()
+  "Swap current row and the one below."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'next 'row))
+
+;;;###autoload
+(defun latex-table-wizard-swap-cell-right ()
+  "Swap content of current cell and the one to the right."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'forward 'cell))
+
+;;;###autoload
+(defun latex-table-wizard-swap-cell-left ()
+  "Swap content of current cell and the one to the left."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'backward 'cell))
+
+;;;###autoload
+(defun latex-table-wizard-swap-cell-down ()
+  "Swap content of current cell and the one below."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'next 'cell))
+
+;;;###autoload
+(defun latex-table-wizard-swap-cell-up ()
+  "Swap content of current cell and the one above."
+  (interactive)
+  (latex-table-wizard--swap-adjacent-line 'previous 'cell))
+
+;;;###autoload
+(defun latex-table-wizard-insert-column ()
+  "Insert empty column to the right of the one at point."
+  (interactive)
+  (save-excursion
+    (let* ((table (latex-table-wizard--parse-table))
+           (current-cell (latex-table-wizard--get-thing 'cell table))
+           (current-column (latex-table-wizard--get-thing 'column table)))
+      (dolist (x current-column)
+        (goto-char (plist-get x :end))
+        (insert " & ")))))
+
+;;;###autoload
+(defun latex-table-wizard-kill-column ()
+  "Kill content of column at point."
+  (interactive)
+  (save-excursion
+    (let* ((table (latex-table-wizard--parse-table))
+           (current-cell (latex-table-wizard--get-thing 'cell table))
+           (current-column (latex-table-wizard--get-thing 'column table))
+           (kills '()))
+      (dolist (x current-column)
+        (let* ((b (plist-get x :start))
+               (next (latex-table-wizard--get-other-cell
+                      'forward t 1 table x))
+               (e (plist-get next :start)))
+          (push (buffer-substring b e) kills)
+          (delete-region b e)))
+      (kill-region (latex-table-wizard--disjoin
+                    (nreverse kills) "\n")))))
+
+;;;###autoload
+(defun latex-table-wizard-insert-row ()
+  "Insert empty row below the one at point."
+  (interactive)
+  (save-excursion
+    (let* ((table (latex-table-wizard--parse-table))
+           (current-cell (latex-table-wizard--get-thing 'cell table))
+           (current-row (latex-table-wizard--get-thing 'row table))
+           (last-in-row (latex-table-wizard--get-extreme 'forward
+                                                         table
+                                                         current-cell)))
+      (goto-char (plist-get last-in-row :end))
+      (if (looking-at (concat "[[:space:]]*\\\\\\\\"))
+          (goto-char (match-end 0))
+        (insert "\\\\"))
+      (insert "\n")
+      (let ((how-many (length current-row)))
+        (dotimes (i (1- how-many))
+          (insert " &"))
+        (insert " \\\\")))))
+
+;;;###autoload
+(defun latex-table-wizard-kill-row ()
+  "Kill row at point."
+  (interactive)
+  (save-excursion
+    (let* ((table (latex-table-wizard--parse-table))
+           (current-cell (latex-table-wizard--get-thing 'cell table))
+           (current-row (latex-table-wizard--get-thing 'row table)))
+      (thread-last (latex-table-wizard--get-env-ends current-row)
+                   (apply #'buffer-substring)
+                   (kill-region)))))
+
+;;;###autoload
+(defun latex-table-wizard-select-cell ()
+  "Add cell at point to selection for swapping."
+  (interactive)
+  (latex-table-wizard--select-thing 'cell))
+
+;;;###autoload
+(defun latex-table-wizard-select-row ()
+  "Add row at point to selection for swapping."
+  (interactive)
+  (latex-table-wizard--select-thing 'row))
+
+;;;###autoload
+(defun latex-table-wizard-select-column ()
+  "Add column at point to selection for swapping."
+  (interactive)
+  (latex-table-wizard--select-thing 'column))
+
+(defun latex-table-wizard-deselect-cell ()
+  "Remove cell at point from selection for swapping."
+  (interactive)
+  (let* ((table (latex-table-wizard--parse-table))
+         (curr-cell (latex-table-wizard--get-thing 'cell table)))
+    (when (member curr-cell latex-table-wizard--selection))
+    (latex-table-wizard--remove-overlays nil
+                                         (plist-get curr-cell :start)
+                                         (plist-get curr-cell :end))
+    (setq latex-table-wizard--selection
+          (remove curr-cell latex-table-wizard--selection))))
+
+(defun latex-table-wizard-deselect-row ()
+  "Remove row at point from selection for swapping."
+  (interactive)
+  (latex-table-wizard--remove-overlays)
+  (setq latex-table-wizard--selection nil))
+
+(defun latex-table-wizard-deselect-column ()
+  "Remove column at point from selection for swapping."
+  (interactive)
+  (latex-table-wizard--remove-overlays)
+  (setq latex-table-wizard--selection nil))
+
+;;;###autoload
+(defun latex-table-wizard-swap ()
+  "Swap selection and thing at point.
+
+Selection is the current value of
+`latex-table-wizard--selection'.  Depending on whether it is a
+cell, a column or a row, swap that with the cell, column or row
+at point.  If it is none of those object, return nil."
+  (interactive)
+  (unless latex-table-wizard--selection
+    (user-error "Select thing to swap first"))
+  (let* ((table (latex-table-wizard--parse-table))
+         (other latex-table-wizard--selection)
+         (type (latex-table-wizard--type-of-selection other))
+         (current (latex-table-wizard--get-thing type table))
+         (land-coord (cons (plist-get current :column)
+                           (plist-get current :row))))
+    (cond ((not type)
+           (latex-table-wizard--cleanup)
+           (setq latex-table-wizard--selection nil))
+          ((eq type 'cell)
+           (latex-table-wizard--swap-cells (car other) current))
+          (t
+           (latex-table-wizard--swap-line type other current)))
+    (latex-table-wizard--remove-overlays table)
+    (latex-table-wizard--hl-cells other)
+    (setq latex-table-wizard--selection nil)))
+
+
+
+;;; Transient
+
+(defconst latex-table-wizard--motion-suffixes
+  '(("f" "move right" latex-table-wizard-right :transient t)
+    ("b" "move left" latex-table-wizard-left :transient t)
+    ("p" "move down" latex-table-wizard-up :transient t)
+    ("n" "move up" latex-table-wizard-down :transient t)
+    ""
+    ("F" "end of row" latex-table-wizard-end-of-row :transient t)
+    ("B" "beginning of row" latex-table-wizard-beginning-of-row :transient t)
+    ("P" "top" latex-table-wizard-top :transient t)
+    ("N" "bottom" latex-table-wizard-bottom :transient t)
+    ""
+    ("a" "beginning of cell" latex-table-wizard-beginning-of-cell :transient t)
+    ("e" "end of cell" latex-table-wizard-end-of-cell :transient t)))
+
+(defconst latex-table-wizard--mark-suffixes
+  '(("x" "exchange point and mark" exchange-point-and-mark :transient t)
+    ("m c" "mark cell" latex-table-wizard-mark-cell :transient t)
+    ("i c" "insert column right" latex-table-wizard-insert-column :transient t)
+    ("i r" "insert row below" latex-table-wizard-insert-row :transient t)
+    ("k c" "kill current column" latex-table-wizard-kill-column :transient t)
+    ("k r" "kill current row" latex-table-wizard-kill-row :transient t)))
+
+(defconst latex-table-wizard--swap-cell-suffixes
+  '(("C-f" "swap cell right" latex-table-wizard-swap-cell-right :transient t)
+    ("C-b" "swap cell left" latex-table-wizard-swap-cell-left :transient t)
+    ("C-p" "swap cell up" latex-table-wizard-swap-cell-up :transient t)
+    ("C-n" "swap cell down" latex-table-wizard-swap-cell-down :transient t)))
+
+(defconst latex-table-wizard--swap-line-suffixes
+  '(("M-f" "swap column right" latex-table-wizard-swap-column-right :transient 
t)
+    ("M-b" "swap column left" latex-table-wizard-swap-column-left :transient t)
+    ("M-p" "swap row up" latex-table-wizard-swap-row-up :transient t)
+    ("M-n" "swap row down" latex-table-wizard-swap-row-down :transient t)))
+
+(defconst latex-table-wizard--select-suffixes
+  '(("SPC" "select cell" latex-table-wizard-select-cell :transient t)
+    ("c" "select column" latex-table-wizard-select-column :transient t)
+    ("r" "select row" latex-table-wizard-select-row :transient t)
+    ("d SPC" "deselect cell" latex-table-wizard-deselect-cell :transient t)
+    ("d c" "select column" latex-table-wizard-deselect-column :transient t)
+    ("d r" "select row" latex-table-wizard-deselect-row :transient t)
+    ("s" "swap selection" latex-table-wizard-swap :transient t)))
+
+(defconst latex-table-wizard--other-suffixes
+  '(("/" "undo" undo :transient t)
+    ("u" "universal argument" universal-argument :transient t)
+    ("RET" "done" transient-quit-one)))
+
+;;;###autoload
+(transient-define-prefix latex-table-wizard-do ()
+  [:description "      LaTeX table wizard"
+                ["Motion" latex-table-wizard--motion-suffixes]
+                ["Swap"
+                 latex-table-wizard--swap-cell-suffixes
+                 ""
+                 latex-table-wizard--swap-line-suffixes
+                 ""
+                 "Other"
+                 latex-table-wizard--other-suffixes]
+                ["Select and swap"
+                 latex-table-wizard--select-suffixes
+                 ""
+                 "Mark, kill and insert" latex-table-wizard--mark-suffixes]])
+
+(defvar latex-table-wizard-bindings-alist nil
+  "Alist specifying keys in transient prefix `latex-table-wizard-do'.
+
+The members of this alist are cons cells of the form:
+
+    (C . K)
+
+where C is the name of an interactive function and K is a string
+specifying the key (same syntax that `kbd' takes as input).
+
+For example adding this cons cell makes the key 'l' bound to
+`latex-table-wizard-right' in the transient prefix
+`latex-table-wizard-do':
+
+    (latex-table-wizard-right .  \"l\")")
+
+(defun latex-table-wizard-modify-bindings (&optional comm-keys-alist)
+  "Modify bindings in transient prefix `latex-table-wizard-do'.
+
+Modify according to the alist COMM-KEYS-ALIST: if nil is passed
+as an argument, use the value of
+`latex-table-wizard-bindings-alist'.
+
+The members of this alist are cons cells of the form:
+
+    (C . K)
+
+where C is the name of an interactive function and K is a string
+specifying the key (same syntax that `kbd' takes as input).
+
+For example adding this cons cell makes the key 'l' bound to
+`latex-table-wizard-right' in the transient prefix
+`latex-table-wizard-do':
+
+    (latex-table-wizard-right .  \"l\")"
+  (macroexpand
+   (transient-define-prefix latex-table-wizard-do ()
+     [:description "      LaTeX table wizard"
+                   ["Motion" latex-table-wizard--motion-suffixes]
+                   ["Swap"
+                    latex-table-wizard--swap-cell-suffixes
+                    ""
+                    latex-table-wizard--swap-line-suffixes
+                    ""
+                    "Other"
+                    latex-table-wizard--other-suffixes]
+                   ["Select and swap"
+                    latex-table-wizard--select-suffixes
+                    ""
+                    "Mark, kill and insert"
+                    latex-table-wizard--mark-suffixes]]))
+  (let* ((new-alist (or comm-keys-alist latex-table-wizard-bindings-alist))
+         (all-commands
+          (list latex-table-wizard--motion-suffixes
+                latex-table-wizard--mark-suffixes
+                latex-table-wizard--swap-cell-suffixes
+                latex-table-wizard--swap-line-suffixes
+                latex-table-wizard--select-suffixes
+                latex-table-wizard--other-suffixes))
+         (def-command-key-alist '()))
+    (dolist (l all-commands)
+      (dolist (x l)
+        (when (listp x)
+          (push (cons (nth 2 x) (nth 0 x)) def-command-key-alist))))
+    (dolist (x new-alist)
+      (let* ((comm (car x))
+             (new-key (cdr x))
+             (def-key (alist-get comm def-command-key-alist)))
+        (transient-suffix-put 'latex-table-wizard-do def-key :key new-key)))))
+
+(advice-add #'latex-table-wizard-do
+            :before #'latex-table-wizard-modify-bindings)
+
+;;; Aesthetics
+
+(defface latex-table-wizard-background-face
+  '((t (:foreground "gray40")))
+  "Face for hiding non-table buffer content.")
+
+(defsubst latex-table-wizard--hide-rest ()
+  "Grey out parts of buffer outside of table at point."
+  (latex-table-wizard--parse-table)
+  (let* ((tab-b (car latex-table-wizard--parsed-table-delims))
+         (tab-e (cdr latex-table-wizard--parsed-table-delims))
+         (ols `(,(make-overlay (point-min) tab-b)
+                ,(make-overlay tab-e (point-max)))))
+    (dolist (x ols)
+      (overlay-put x 'tabl-outside-ol t)
+      (overlay-put x 'face 'latex-table-wizard-background-face))))
+
+(defun latex-table-wizard--cleanup ()
+  "Remove overlays created by 'latex-table-wizard' in the buffer."
+  (setq latex-table-wizard--selection nil)
+  (when-let ((lims latex-table-wizard--parsed-table-delims))
+    (remove-overlays (point-min) (point-max) 'tabl-inside-ol t)
+    (remove-overlays (point-min) (point-max) 'tabl-outside-ol t)))
+
+(defsubst latex-table-wizard--get-out ()
+  "If point is on column or row delimiter, move to its beginning."
+  (latex-table-wizard--set-current-values)
+  (when-let ((macro (latex-table-wizard--point-on-regexp-p
+                     (latex-table-wizard--disjoin
+                      (list (regexp-opt
+                             (cl-union
+                              latex-table-wizard--current-row-delims
+                              latex-table-wizard--current-col-delims))
+                            latex-table-wizard--macro-re))
+                     0 (line-beginning-position))))
+    (thread-last macro
+                 (nth 1)
+                 (1-)
+                 (goto-char))))
+
+(advice-add #'latex-table-wizard-do :after #'latex-table-wizard--get-out)
+(advice-add #'latex-table-wizard-do :after #'latex-table-wizard--hide-rest)
+(advice-add #'transient-quit-one :before #'latex-table-wizard--cleanup)
+(add-hook 'before-save-hook #'latex-table-wizard--cleanup)
+
+(provide 'latex-table-wizard)
+
+;;; _
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+
+;;; latex-table-wizard.el ends here
diff --git a/move-01.gif b/move-01.gif
new file mode 100644
index 0000000000..467c5bdb25
Binary files /dev/null and b/move-01.gif differ
diff --git a/readme.org b/readme.org
new file mode 100644
index 0000000000..e5a3c93e94
--- /dev/null
+++ b/readme.org
@@ -0,0 +1,245 @@
+#+TITLE: LaTeX table wizard - Magic editing of LaTeX tables
+#+SUBTITLE: for version {{{version}}}
+#+AUTHOR: Enrico Flor
+#+EMAIL: enrico@eflor.net
+
+#+OPTIONS: ':t toc:t author:t email:t
+#+MACRO: version 0.1.0
+#+MACRO: updated last updated 14 November 2022
+
+Copyright (C) 2022 Enrico Flor.
+
+     Permission is granted to copy, distribute and/or modify this
+     document under the terms of the GNU Free Documentation License,
+     Version 1.3 or any later version published by the Free Software
+     Foundation; with no Invariant Sections, with the Front-Cover Texts
+     being “A GNU Manual,” and with the Back-Cover Texts as in (a)
+     below.  A copy of the license is included in the section entitled
+     “GNU Free Documentation License.”
+
+     (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
+     modify this GNU manual.”
+* Introduction
+
+One of org-mode's magic features is its table editing capabilities.
+The goal of this package is to replicate that luxury for LaTeX
+table(-like) environments.
+
+LaTeX-table-wizard's UI is based on 
[[https://elpa.gnu.org/packages/transient.html][transient]].  While the user can
+change all the bindings, and can use all the commands without the
+transient interface, this readme will refer to the commands through
+the default bindings as they can be seen in the transient below.
+
+[[./default-transient.png][Transient interface]]
+
+The transient interface is invoked through the ~latex-table-wizard-do~
+command, and exited, as usual, with ~C-g~.
+
+An important feature of LaTeX-table-wizard is that it tries to be
+smart: for instance, it should not be fooled if the current table-like
+environments contains embedded tables (that is, other tabular
+environments inside of its cells).  The table is parsed so that these
+big cells are treated like any other cell.
+
+[[./move-01.gif]]
+
+[[./select-01.gif]]
+
+[[./swap-01.gif]]
+
+* Available commands
+For now, we will assume a standard LaTeX syntax for tabular
+environments, where ~&~ delimits columns and ~\\~ rows (see 
[[#user-defined-envs][below]] for info
+as to how to specify additional syntaxes).
+
+Whenever we say "current" we mean "at point".
+** Relative motion commands
+
+These commands move point N cells to the right, left, down, and up.  N
+is passed as a prefix argument, and if it's not passed, it defaults
+to 1.
+
+| Command                  | Default key |
+|--------------------------+-------------|
+| ~latex-table-wizard-right~ | ~f~           |
+| ~latex-table-wizard-left~  | ~b~           |
+| ~latex-table-wizard-down~  | ~n~           |
+| ~latex-table-wizard-up~    | ~p~           |
+
+With just one of these you can get anywhere you want in the table:
+
+#+begin_src LaTeX
+\begin{tabular}{lll}
+  A0 & B0 & C0 \\\hline
+  A1 & B1 & C1 \\
+  A2 & B2 & C2
+\end{tabular}
+#+end_src
+
+This is because these commands try to Do What You Mean if there is no
+suitable cell to move to:
+
++ Point on ~C0~, ~latex-table-wizard-right~ ⇒ point on ~A1~
++ Point on ~A0~, ~latex-table-wizard-left~ ⇒ point on ~C2~
++ Point on ~C2~, ~latex-table-wizard-down~ ⇒ point on ~A0~
++ Point on ~B0~, ~latex-table-wizard-up~ ⇒ point on ~A2~
+
+and so on.
+** Absolute motion commands
+
+| Command                              | Default key | Move to...              
      |
+|--------------------------------------+-------------+-------------------------------|
+| ~latex-table-wizard-beginning-of-cell~ | ~a~           | end of current cell 
          |
+| ~latex-table-wizard-end-of-cell~       | ~e~           | beginning of 
current cell     |
+| ~latex-table-wizard-beginning-of-row~  | ~B~           | leftmost cell in 
current row  |
+| ~latex-table-wizard-end-of-row~        | ~F~           | rightmost cell in 
current row |
+| ~latex-table-wizard-bottom~            | ~N~           | bottom cell in 
current column |
+| ~latex-table-wizard-top~               | ~P~           | top cell in current 
column    |
+** Mark, kill and insert commands
+| Command                          | Default key |                             
               |
+|----------------------------------+-------------+--------------------------------------------|
+| ~latex-table-wizard-mark-cell~     | ~m c~         | mark current cell       
                   |
+| ~latex-table-wizard-insert-column~ | ~i c~         | insert empty column to 
the right           |
+| ~latex-table-wizard-insert-row~    | ~i r~         | insert row below        
                   |
+| ~latex-table-wizard-kill-column~   | ~k c~         | add content of current 
column to kill ring |
+| ~latex-table-wizard-kill-row~      | ~k r~         | add content of current 
row to kill ring    |
+| ~exchange-point-and-mark~          | ~x~           |                         
                   |
+** Swap adjacent fields
+
+| Command                              | Default key | Swap current...         
         |
+|--------------------------------------+-------------+----------------------------------|
+| ~latex-table-wizard-swap-cell-right~   | ~C-f~         | cell with the one 
to the right   |
+| ~latex-table-wizard-swap-cell-left~    | ~C-b~         | cell with the one 
to the left    |
+| ~latex-table-wizard-swap-cell-down~    | ~C-n~         | cell with the one 
below          |
+| ~latex-table-wizard-swap-cell-up~      | ~C-p~         | cell with the one 
above          |
+| ~latex-table-wizard-swap-column-right~ | ~M-f~         | column with the one 
to the right |
+| ~latex-table-wizard-swap-column-left~  | ~M-b~         | column with the one 
to the left  |
+| ~latex-table-wizard-swap-row-down~     | ~M-n~         | row with the one 
below           |
+| ~latex-table-wizard-swap-row-up~       | ~M-p~         | row with the one 
above           |
+
+For these commands, think of the cells and columns as circular: if
+there is no item in the direction given, the target is the one on the
+opposite end of the current cell.  So for example:
+
+#+begin_src LaTeX
+\begin{tabular}{lll}
+  A0 & B0 & C0 \\\hline
+  A1 & B1 & C1 \\
+  A2 & B2 & C2
+\end{tabular}
+#+end_src
+
+This is because these commands try to Do What You Mean if there is no
+suitable cell to move to:
+
++ Point on ~B0~, ~latex-table-wizard-swap-row-up~
+  ⇒
+#+begin_src LaTeX
+\begin{tabular}{lll}
+ A2  & B2  & C2  \\\hline
+  A1 & B1 & C1 \\
+ A0  & B0  & C0
+\end{tabular}
+#+end_src
++ Point on ~C2~, ~latex-table-wizard-swap-cell-right~
+  ⇒
+#+begin_src latex
+\begin{tabular}{lll}
+ C0  & B0 & A0  \\\hline
+  A1 & B1 & C1 \\
+  A2 & B2 & C2
+\end{tabular}
+#+end_src
+
+** Swap arbitrary fields
+To swap arbitrary fields one must first *select* something and then
+move point somewhere else and perform the swap.  Importantly,
+*selecting does not mean marking*: the mark is not even moved when
+selecting.
+
+The simplest case is one in which the current cell, column or row are
+selected:
+
+| Command                          | Default key | Select current... |
+|----------------------------------+-------------+-------------------|
+| ~latex-table-wizard-select-cell~   | ~SPC~         | cell              |
+| ~latex-table-wizard-select-column~ | ~c~           | column            |
+| ~latex-table-wizard-select-row~    | ~r~           | row               |
+
+Things can be deselected too:
+
+| Command                              | Default key | Deselect current... |
+|--------------------------------------+-------------+---------------------|
+| ~latex-table-wizard-deselect-cell~   | ~d SPC~     | cell                |
+| ~latex-table-wizard-deselect-column~ | ~d c~       | column              |
+| ~latex-table-wizard-deselect-row~    | ~d r~       | row                 |
+
+Once things are selected, you move point somewhere else in the table
+(with the above mentioned motion commands), and then:
+
+| ~latex-table-wizard-swap~ | ~s~ | swap selection and current thing |
+
+What is swapped depends on what is selected: if the selection was only
+a cell, then that cell and the current one are swapped.  If it was (a
+potentially discontinuous segment of) a column or a row, then that
+selection is swapped with the current column or row or the
+corresponding portion thereof.  If you selected multiple cell that are
+not part of the same column or row, the swap won't happen
+(LaTeX-table-wizard doesn't know what to do).
+
+* Customization
+** Change keybindings
+To change the default keybindings you give an appropriate value to the
+association list ~latex-table-wizard-bindings-alist~ and then call the
+function ~latex-table-wizard-modify-bindings~.
+
+Suppose you want to keep all the defaults except that you want to bind
+~l~ to ~latex-table-wizard-right~ and ~s l~ to
+~latex-table-wizard-swap-cell-right~.  To achieve that add this to
+your configuration of ~latex-table-wizard~:
+
+#+begin_src emacs-lisp
+(setq latex-table-wizard-bindings-alist
+      '((latex-table-wizard-right . "l")
+        (latex-table-wizard-swap-cell-right . "s l")))
+#+end_src
+
+The syntax of the values (the keys) is the same accepted by the built
+in ~kbd~ macro.
+** Define rules for new environments
+:PROPERTIES:
+:CUSTOM_ID: user-defined-envs
+:END:
+Remember the default values used for parsing table environments:
+
+#+begin_src emacs-lisp
+(defconst latex-table-wizard-column-delimiters '("[^\\\\]&")
+  "List of regexps matching column delimiters.")
+
+(defconst latex-table-wizard-row-delimiters '("\\\\\\\\")
+  "List of regexps matching row delimiters.")
+
+(defvar latex-table-wizard-hline-macros '("hline"
+                                          "midrule"
+                                          "toprule"
+                                          "bottomrule"))
+#+end_src
+
+ LaTeX-table-wizard will always presume the table you want operate on
+ has a syntax specified like this.  But suppose you use different
+ environments with non-standard syntax: suppose you define a
+ table-like environment of your choice, let's call it ~mytable~, that
+ uses ~!ROW~ and ~!COL~ instead of ~&~ and ~\\~ as delimiters, and a macro
+ ~\horizontal~ for horizontal lines.  When you are in a ~mytable~
+ environments, you want LaTeX-table-wizard to adapt to this new
+ syntax.
+
+ All you need to do add an appropriate cons cell to the
+ ~latex-table-wizard-new-environments-alist~ association list, mapping
+ the name of the environment, as a string, to a property list
+ specifying the values.  For the case of ~mytable~ you would do:
+
+ #+begin_src emacs-lisp
+(add-to-list 'latex-table-wizard-new-environments-alist
+             '("mytable" . (:col ("!COL") :row ("!ROW") :lines 
("horizontal"))))
+ #+end_src
diff --git a/select-01.gif b/select-01.gif
new file mode 100644
index 0000000000..8a1e20c8cb
Binary files /dev/null and b/select-01.gif differ
diff --git a/swap-01.gif b/swap-01.gif
new file mode 100644
index 0000000000..2be51568fc
Binary files /dev/null and b/swap-01.gif differ



reply via email to

[Prev in Thread] Current Thread [Next in Thread]