removed emacs.d; its unmaintained anyway
This commit is contained in:
17
.emacs.d/.gitignore
vendored
17
.emacs.d/.gitignore
vendored
@@ -1,17 +0,0 @@
|
|||||||
*~
|
|
||||||
/auto-save-list/
|
|
||||||
/bak/
|
|
||||||
/elpa/
|
|
||||||
/ido.last
|
|
||||||
/ohai-personal-taste.el
|
|
||||||
/recentf
|
|
||||||
/smex-items
|
|
||||||
/custom.el
|
|
||||||
/eshell/
|
|
||||||
/projectile-bookmarks.eld
|
|
||||||
/.mc-lists.el
|
|
||||||
/user.el
|
|
||||||
/var/
|
|
||||||
/tramp
|
|
||||||
/url/
|
|
||||||
/session.*
|
|
Binary file not shown.
Before Width: | Height: | Size: 99 KiB |
@@ -1,9 +0,0 @@
|
|||||||
install:
|
|
||||||
- sudo add-apt-repository -y ppa:ubuntu-elisp/ppa &&
|
|
||||||
sudo apt-get -qq update &&
|
|
||||||
sudo apt-get -qq -f install &&
|
|
||||||
sudo apt-get -qq install emacs-snapshot
|
|
||||||
|
|
||||||
script:
|
|
||||||
- ln -s . .emacs.d &&
|
|
||||||
HOME=`pwd` emacs --batch -Q --eval "(load-file \"ohai/ohai-test.el\")"
|
|
674
.emacs.d/COPYING
674
.emacs.d/COPYING
@@ -1,674 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://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 <http://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
|
|
||||||
<http://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
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@@ -1,60 +0,0 @@
|
|||||||
* Ohai Emacs
|
|
||||||
|
|
||||||
While it is certainly true that Emacs is the most powerful text editor in the world, your first impression of it may be less favourable, because its default configuration really just isn't all that great.
|
|
||||||
|
|
||||||
But now there is Ohai Emacs! Simply install Ohai Emacs as your emacs.d, and you will be ready to bask in the full radiance of Holy Emacs in no time at all.
|
|
||||||
|
|
||||||
There is even a configuration [[https://i.chzbgr.com/maxW500/8443050752/h55957A15/][wizard]]!
|
|
||||||
|
|
||||||
[[./.ohai-emacs/ohai-emacs.jpg]]
|
|
||||||
|
|
||||||
** Installation
|
|
||||||
|
|
||||||
If you don't have it installed already, go get a copy of [[http://www.gnu.org/software/emacs/#Obtaining][GNU Emacs]] version 24.4 or later.
|
|
||||||
|
|
||||||
If you have an emacs.d already, move it out of the way (~mv ~/.emacs.d ~/.emacs.d.bak~) or get rid of it (~rm -rf ~/.emacs.d~) first.
|
|
||||||
|
|
||||||
To download Ohai Emacs as your new emacs.d:
|
|
||||||
|
|
||||||
#+begin_src sh
|
|
||||||
$ git clone https://github.com/bodil/ohai-emacs.git ~/.emacs.d
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
That's it! Now, the next time you start Emacs, Ohai Emacs will ask you a few questions about how you like things to be, and go on the internets and download some fresh packages for you. In a little while, it will be ready for your emacsing.
|
|
||||||
|
|
||||||
** Usage
|
|
||||||
|
|
||||||
A full feature list is pending. A quick overview:
|
|
||||||
|
|
||||||
- Carefully styled for a fashionable look.
|
|
||||||
- Improved navigation, editing and code style settings.
|
|
||||||
- Magit, the premier git frontend.
|
|
||||||
- Smart autocomplete with company-mode.
|
|
||||||
- Flycheck.
|
|
||||||
- Yasnippet.
|
|
||||||
- Paredit for Emacs Lisp.
|
|
||||||
- Improved JS and HTML modes with powerful refactoring tools.
|
|
||||||
- Nyan Cat.
|
|
||||||
|
|
||||||
*** Learning From Emacs Lisp
|
|
||||||
|
|
||||||
While Ohai Emacs helps you get started quickly and without frustration, you must eventually learn Emacs Lisp in order to become an Emacs Master. The Ohai Emacs source code contains numerous comments designed to explain, often in detail, what it's doing. The best (if not the fastest) way to learn what Ohai Emacs can do for you is to read the source.
|
|
||||||
|
|
||||||
Start at ~.emacs.d/init.el~. This sets up the basic environment, and loads each Ohai Emacs module from the ~.emacs.d/modules~ directory in turn. Read through the ~.el~ file in the module directory that are of interest to you, and you will find they explain the changes they make, often pointing you to useful documentation for the more powerful features.
|
|
||||||
|
|
||||||
** License
|
|
||||||
|
|
||||||
Copyright 2015 Bodil Stokke
|
|
||||||
|
|
||||||
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 http://www.gnu.org/licenses/.
|
|
@@ -1,676 +0,0 @@
|
|||||||
(1
|
|
||||||
(ace-window .
|
|
||||||
[(0 9 0)
|
|
||||||
((avy
|
|
||||||
(0 2 0)))
|
|
||||||
"Quickly switch windows." single
|
|
||||||
((:url . "https://github.com/abo-abo/ace-window")
|
|
||||||
(:keywords "window" "location"))])
|
|
||||||
(ack .
|
|
||||||
[(1 3)
|
|
||||||
nil "Interface to ack-like source code search tools" tar
|
|
||||||
((:keywords "tools" "processes" "convenience")
|
|
||||||
(:url . "https://github.com/leoliu/ack-el"))])
|
|
||||||
(ada-mode .
|
|
||||||
[(5 1 8)
|
|
||||||
((wisi
|
|
||||||
(1 1 1))
|
|
||||||
(cl-lib
|
|
||||||
(0 4))
|
|
||||||
(emacs
|
|
||||||
(24 2)))
|
|
||||||
"major-mode for editing Ada sources" tar
|
|
||||||
((:keywords "languages" "ada")
|
|
||||||
(:url . "http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html"))])
|
|
||||||
(ada-ref-man .
|
|
||||||
[(2012 0)
|
|
||||||
nil "Ada Reference Manual 2012" tar
|
|
||||||
((:keywords "languages" "ada")
|
|
||||||
(:url . "http://stephe-leake.org/ada/arm.html"))])
|
|
||||||
(adaptive-wrap .
|
|
||||||
[(0 5)
|
|
||||||
nil "Smart line-wrapping with wrap-prefix" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/adaptive-wrap.html")
|
|
||||||
(:keywords))])
|
|
||||||
(adjust-parens .
|
|
||||||
[(3 0)
|
|
||||||
nil "Indent and dedent Lisp code, automatically adjust close parens" tar
|
|
||||||
((:url . "http://elpa.gnu.org/packages/adjust-parens.html"))])
|
|
||||||
(aggressive-indent .
|
|
||||||
[(1 0 2)
|
|
||||||
((emacs
|
|
||||||
(24 1))
|
|
||||||
(names
|
|
||||||
(20150125 9))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Minor mode to aggressively keep your code always indented" single
|
|
||||||
((:url . "http://github.com/Malabarba/aggressive-indent-mode")
|
|
||||||
(:keywords "indent" "lisp" "maint" "tools"))])
|
|
||||||
(ahungry-theme .
|
|
||||||
[(1 0 6)
|
|
||||||
((emacs
|
|
||||||
(24)))
|
|
||||||
"Ahungry color theme for Emacs. Make sure to (load-theme 'ahungry)." tar
|
|
||||||
((:keywords "ahungry" "palette" "color" "theme" "emacs" "color-theme" "deftheme")
|
|
||||||
(:url . "https://github.com/ahungry/color-theme-ahungry"))])
|
|
||||||
(all .
|
|
||||||
[(1 0)
|
|
||||||
nil "Edit all lines matching a given regexp" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/all.html")
|
|
||||||
(:keywords "matching"))])
|
|
||||||
(ascii-art-to-unicode .
|
|
||||||
[(1 9)
|
|
||||||
nil "a small artist adjunct" single
|
|
||||||
((:url . "http://www.gnuvola.org/software/aa2u/")
|
|
||||||
(:keywords "ascii" "unicode" "box-drawing"))])
|
|
||||||
(auctex .
|
|
||||||
[(11 88 6)
|
|
||||||
nil "Integrated environment for *TeX*" tar
|
|
||||||
((:url . "http://www.gnu.org/software/auctex/"))])
|
|
||||||
(aumix-mode .
|
|
||||||
[(7)
|
|
||||||
nil "run the aumix program in a buffer" single
|
|
||||||
((:url . "http://user42.tuxfamily.org/aumix-mode/index.html")
|
|
||||||
(:keywords "multimedia" "mixer" "aumix"))])
|
|
||||||
(auto-overlays .
|
|
||||||
[(0 10 9)
|
|
||||||
nil "Automatic regexp-delimited overlays" tar
|
|
||||||
((:keywords "extensions")
|
|
||||||
(:url . "http://www.dr-qubit.org/emacs.php"))])
|
|
||||||
(avy .
|
|
||||||
[(0 2 1)
|
|
||||||
((emacs
|
|
||||||
(24 1))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"set-based completion" tar
|
|
||||||
((:keywords "point" "location")
|
|
||||||
(:url . "https://github.com/abo-abo/avy"))])
|
|
||||||
(bug-hunter .
|
|
||||||
[(0 2)
|
|
||||||
((seq
|
|
||||||
(1 3))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Hunt down errors in elisp files" single
|
|
||||||
((:url . "http://github.com/Malabarba/elisp-bug-hunter")
|
|
||||||
(:keywords "lisp"))])
|
|
||||||
(caps-lock .
|
|
||||||
[(1 0)
|
|
||||||
nil "Caps-lock as a minor mode" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/caps-lock.html")
|
|
||||||
(:keywords))])
|
|
||||||
(chess .
|
|
||||||
[(2 0 4)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Play chess in GNU Emacs" tar
|
|
||||||
((:keywords "games")
|
|
||||||
(:url . "http://elpa.gnu.org/packages/chess.html"))])
|
|
||||||
(cl-generic .
|
|
||||||
[(0 2)
|
|
||||||
nil "Forward cl-generic compatibility for Emacs<25" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/cl-generic.html")
|
|
||||||
(:keywords))])
|
|
||||||
(cl-lib .
|
|
||||||
[(0 5)
|
|
||||||
nil "Properly prefixed CL functions and macros" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/cl-lib.html")
|
|
||||||
(:keywords))])
|
|
||||||
(coffee-mode .
|
|
||||||
[(0 4 1 1)
|
|
||||||
nil "Major mode for CoffeeScript files" single
|
|
||||||
((:url . "http://github.com/defunkt/coffee-mode")
|
|
||||||
(:keywords "coffeescript" "major" "mode"))])
|
|
||||||
(company .
|
|
||||||
[(0 8 12)
|
|
||||||
((emacs
|
|
||||||
(24 1))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Modular text completion framework" tar
|
|
||||||
((:keywords "abbrev" "convenience" "matching")
|
|
||||||
(:url . "http://company-mode.github.io/"))])
|
|
||||||
(company-statistics .
|
|
||||||
[(0 1 1)
|
|
||||||
((emacs
|
|
||||||
(24 3))
|
|
||||||
(company
|
|
||||||
(0 8 5)))
|
|
||||||
"Sort candidates using completion history" tar
|
|
||||||
((:keywords "abbrev" "convenience" "matching")
|
|
||||||
(:url . "https://github.com/company-mode/company-statistics"))])
|
|
||||||
(context-coloring .
|
|
||||||
[(6 3 0)
|
|
||||||
((emacs
|
|
||||||
(24))
|
|
||||||
(js2-mode
|
|
||||||
(20150126)))
|
|
||||||
"Highlight by scope" single
|
|
||||||
((:url . "https://github.com/jacksonrayhamilton/context-coloring")
|
|
||||||
(:keywords "convenience" "faces" "tools"))])
|
|
||||||
(crisp .
|
|
||||||
[(1 3 4)
|
|
||||||
nil "CRiSP/Brief Emacs emulator" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/crisp.html")
|
|
||||||
(:keywords "emulations" "brief" "crisp"))])
|
|
||||||
(csv-mode .
|
|
||||||
[(1 4)
|
|
||||||
nil "Major mode for editing comma/char separated values" single
|
|
||||||
((:url . "http://centaur.maths.qmul.ac.uk/Emacs/")
|
|
||||||
(:keywords "convenience"))])
|
|
||||||
(darkroom .
|
|
||||||
[(0 1)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Remove visual distractions and focus on writing" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/darkroom.html")
|
|
||||||
(:keywords "convenience" "emulations"))])
|
|
||||||
(dbus-codegen .
|
|
||||||
[(0 1)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Lisp code generation for D-Bus." single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/dbus-codegen.html")
|
|
||||||
(:keywords "comm" "dbus" "convenience"))])
|
|
||||||
(debbugs .
|
|
||||||
[(0 7)
|
|
||||||
nil "SOAP library to access debbugs servers" tar
|
|
||||||
((:keywords "comm" "hypermedia")
|
|
||||||
(:url . "http://elpa.gnu.org/packages/debbugs.html"))])
|
|
||||||
(dict-tree .
|
|
||||||
[(0 12 8)
|
|
||||||
((trie
|
|
||||||
(0 2 5))
|
|
||||||
(tNFA
|
|
||||||
(0 1 1))
|
|
||||||
(heap
|
|
||||||
(0 3)))
|
|
||||||
"Dictionary data structure" single
|
|
||||||
((:url . "http://www.dr-qubit.org/emacs.php")
|
|
||||||
(:keywords "extensions" "matching" "data structures trie" "tree" "dictionary" "completion" "regexp"))])
|
|
||||||
(diff-hl .
|
|
||||||
[(1 7 0)
|
|
||||||
((cl-lib
|
|
||||||
(0 2)))
|
|
||||||
"Highlight uncommitted changes" tar
|
|
||||||
((:keywords "vc" "diff")
|
|
||||||
(:url . "https://github.com/dgutov/diff-hl"))])
|
|
||||||
(dismal .
|
|
||||||
[(1 5)
|
|
||||||
((cl-lib
|
|
||||||
(0)))
|
|
||||||
"Dis Mode Ain't Lotus: Spreadsheet program Emacs" tar
|
|
||||||
((:url . "http://elpa.gnu.org/packages/dismal.html"))])
|
|
||||||
(djvu .
|
|
||||||
[(0 5)
|
|
||||||
nil "Edit and view Djvu files via djvused" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/djvu.html")
|
|
||||||
(:keywords "files" "wp"))])
|
|
||||||
(docbook .
|
|
||||||
[(0 1)
|
|
||||||
nil "Info-like viewer for DocBook" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/docbook.html")
|
|
||||||
(:keywords "docs" "help"))])
|
|
||||||
(easy-kill .
|
|
||||||
[(0 9 3)
|
|
||||||
((emacs
|
|
||||||
(24))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"kill & mark things easily" tar
|
|
||||||
((:keywords "killing" "convenience")
|
|
||||||
(:url . "https://github.com/leoliu/easy-kill"))])
|
|
||||||
(ediprolog .
|
|
||||||
[(1 0)
|
|
||||||
nil "Emacs Does Interactive Prolog" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/ediprolog.html")
|
|
||||||
(:keywords "languages" "processes"))])
|
|
||||||
(eldoc-eval .
|
|
||||||
[(0 1)
|
|
||||||
nil "Enable eldoc support when minibuffer is in use." single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/eldoc-eval.html")
|
|
||||||
(:keywords))])
|
|
||||||
(electric-spacing .
|
|
||||||
[(5 0)
|
|
||||||
nil "Insert operators with surrounding spaces smartly" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/electric-spacing.html")
|
|
||||||
(:keywords))])
|
|
||||||
(enwc .
|
|
||||||
[(1 0)
|
|
||||||
nil "The Emacs Network Client" tar
|
|
||||||
((:keywords "enwc" "network" "wicd" "manager" "nm")
|
|
||||||
(:url . "http://elpa.gnu.org/packages/enwc.html"))])
|
|
||||||
(epoch-view .
|
|
||||||
[(0 0 1)
|
|
||||||
nil "Minor mode to visualize epoch timestamps" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/epoch-view.html")
|
|
||||||
(:keywords "data" "timestamp" "epoch" "unix"))])
|
|
||||||
(ergoemacs-mode .
|
|
||||||
[(5 14 7 3)
|
|
||||||
((emacs
|
|
||||||
(24 1))
|
|
||||||
(undo-tree
|
|
||||||
(0 6 5)))
|
|
||||||
"Emacs mode based on common modern interface and ergonomics." tar
|
|
||||||
((:keywords "convenience")
|
|
||||||
(:url . "https://github.com/ergoemacs/ergoemacs-mode"))])
|
|
||||||
(f90-interface-browser .
|
|
||||||
[(1 1)
|
|
||||||
nil "Parse and browse f90 interfaces" single
|
|
||||||
((:url . "http://github.com/wence-/f90-iface/")
|
|
||||||
(:keywords))])
|
|
||||||
(flylisp .
|
|
||||||
[(0 2)
|
|
||||||
((emacs
|
|
||||||
(24 1))
|
|
||||||
(cl-lib
|
|
||||||
(0 4)))
|
|
||||||
"Color unbalanced parentheses and parentheses inconsistent with indentation" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/flylisp.html")
|
|
||||||
(:keywords))])
|
|
||||||
(ggtags .
|
|
||||||
[(0 8 10)
|
|
||||||
((emacs
|
|
||||||
(24))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"emacs frontend to GNU Global source code tagging system" single
|
|
||||||
((:url . "https://github.com/leoliu/ggtags")
|
|
||||||
(:keywords "tools" "convenience"))])
|
|
||||||
(gnorb .
|
|
||||||
[(1 1 1)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Glue code between Gnus, Org, and BBDB" tar
|
|
||||||
((:keywords "mail" "org" "gnus" "bbdb" "todo" "task")
|
|
||||||
(:url . "https://github.com/girzel/gnorb"))])
|
|
||||||
(gnugo .
|
|
||||||
[(3 0 0)
|
|
||||||
((ascii-art-to-unicode
|
|
||||||
(1 5))
|
|
||||||
(xpm
|
|
||||||
(1 0 1))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"play GNU Go in a buffer" tar
|
|
||||||
((:keywords "games" "processes")
|
|
||||||
(:url . "http://www.gnuvola.org/software/gnugo/"))])
|
|
||||||
(heap .
|
|
||||||
[(0 3)
|
|
||||||
nil "Heap (a.k.a. priority queue) data structure" single
|
|
||||||
((:url . "http://www.dr-qubit.org/emacs.php")
|
|
||||||
(:keywords "extensions" "data structures" "heap" "priority queue"))])
|
|
||||||
(hydra .
|
|
||||||
[(0 13 2)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Make bindings that stick around." tar
|
|
||||||
((:keywords "bindings")
|
|
||||||
(:url . "https://github.com/abo-abo/hydra"))])
|
|
||||||
(ioccur .
|
|
||||||
[(2 4)
|
|
||||||
nil "Incremental occur" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/ioccur.html")
|
|
||||||
(:keywords))])
|
|
||||||
(iterators .
|
|
||||||
[(0 1)
|
|
||||||
((emacs
|
|
||||||
(25)))
|
|
||||||
"Functions for working with iterators" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/iterators.html")
|
|
||||||
(:keywords "extensions" "elisp"))])
|
|
||||||
(javaimp .
|
|
||||||
[(0 5)
|
|
||||||
nil "Add and reorder Java import statements in Maven projects" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/javaimp.html")
|
|
||||||
(:keywords "java" "maven" "programming"))])
|
|
||||||
(jgraph-mode .
|
|
||||||
[(1 1)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Major mode for Jgraph files" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/jgraph-mode.html")
|
|
||||||
(:keywords "tex" "wp"))])
|
|
||||||
(js2-mode .
|
|
||||||
[(20150202)
|
|
||||||
((emacs
|
|
||||||
(24 1))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Improved JavaScript editing mode" tar
|
|
||||||
((:keywords "languages" "javascript")
|
|
||||||
(:url . "https://github.com/mooz/js2-mode/"))])
|
|
||||||
(jumpc .
|
|
||||||
[(3 0)
|
|
||||||
nil "jump to previous insertion points" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/jumpc.html")
|
|
||||||
(:keywords))])
|
|
||||||
(let-alist .
|
|
||||||
[(1 0 4)
|
|
||||||
nil "Easily let-bind values of an assoc-list by their names" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/let-alist.html")
|
|
||||||
(:keywords "extensions" "lisp"))])
|
|
||||||
(lex .
|
|
||||||
[(1 1)
|
|
||||||
nil "Lexical analyser construction" tar
|
|
||||||
((:url . "http://elpa.gnu.org/packages/lex.html"))])
|
|
||||||
(lmc .
|
|
||||||
[(1 3)
|
|
||||||
nil "Little Man Computer in Elisp" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/lmc.html")
|
|
||||||
(:keywords))])
|
|
||||||
(load-dir .
|
|
||||||
[(0 0 3)
|
|
||||||
nil "Load all Emacs Lisp files in a given directory" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/load-dir.html")
|
|
||||||
(:keywords "lisp" "files" "convenience"))])
|
|
||||||
(load-relative .
|
|
||||||
[(1 2)
|
|
||||||
nil "relative file load (within a multi-file Emacs package)" single
|
|
||||||
((:url . "http://github.com/rocky/emacs-load-relative")
|
|
||||||
(:keywords "internal"))])
|
|
||||||
(loc-changes .
|
|
||||||
[(1 2)
|
|
||||||
nil "keep track of positions even after buffer changes" single
|
|
||||||
((:url . "http://github.com/rocky/emacs-loc-changes")
|
|
||||||
(:keywords))])
|
|
||||||
(markchars .
|
|
||||||
[(0 2 0)
|
|
||||||
nil "Mark chars fitting certain characteristics" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/markchars.html")
|
|
||||||
(:keywords))])
|
|
||||||
(memory-usage .
|
|
||||||
[(0 2)
|
|
||||||
nil "Analyze the memory usage of Emacs in various ways" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/memory-usage.html")
|
|
||||||
(:keywords "maint"))])
|
|
||||||
(metar .
|
|
||||||
[(0 1)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Retrieve and decode METAR weather information" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/metar.html")
|
|
||||||
(:keywords "comm"))])
|
|
||||||
(minibuffer-line .
|
|
||||||
[(0 1)
|
|
||||||
nil "Display status info in the minibuffer window" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/minibuffer-line.html")
|
|
||||||
(:keywords))])
|
|
||||||
(minimap .
|
|
||||||
[(1 2)
|
|
||||||
nil "Sidebar showing a \"mini-map\" of a buffer" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/minimap.html")
|
|
||||||
(:keywords))])
|
|
||||||
(muse .
|
|
||||||
[(3 20)
|
|
||||||
nil "Authoring and publishing tool for Emacs" tar
|
|
||||||
((:keywords "hypermedia")
|
|
||||||
(:url . "http://mwolson.org/projects/EmacsMuse.html"))])
|
|
||||||
(names .
|
|
||||||
[(20150115 1)
|
|
||||||
((emacs
|
|
||||||
(24 1))
|
|
||||||
(cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Namespaces for emacs-lisp. Avoid name clobbering without hiding symbols." tar
|
|
||||||
((:keywords "extensions" "lisp")
|
|
||||||
(:url . "http://github.com/Bruce-Connor/names"))])
|
|
||||||
(nhexl-mode .
|
|
||||||
[(0 1)
|
|
||||||
nil "Minor mode to edit files via hex-dump format" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/nhexl-mode.html")
|
|
||||||
(:keywords "data"))])
|
|
||||||
(nlinum .
|
|
||||||
[(1 6)
|
|
||||||
nil "Show line numbers in the margin" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/nlinum.html")
|
|
||||||
(:keywords "convenience"))])
|
|
||||||
(notes-mode .
|
|
||||||
[(1 30)
|
|
||||||
nil "Indexing system for on-line note-taking" tar
|
|
||||||
((:url . "http://elpa.gnu.org/packages/notes-mode.html"))])
|
|
||||||
(num3-mode .
|
|
||||||
[(1 2)
|
|
||||||
nil "highlight groups of digits in long numbers" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/num3-mode.html")
|
|
||||||
(:keywords "faces" "minor-mode"))])
|
|
||||||
(oauth2 .
|
|
||||||
[(0 10)
|
|
||||||
nil "OAuth 2.0 Authorization Protocol" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/oauth2.html")
|
|
||||||
(:keywords "comm"))])
|
|
||||||
(omn-mode .
|
|
||||||
[(1 0)
|
|
||||||
nil "Support for OWL Manchester Notation" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/omn-mode.html")
|
|
||||||
(:keywords))])
|
|
||||||
(org .
|
|
||||||
[(20150608)
|
|
||||||
nil "Outline-based notes management and organizer" tar nil])
|
|
||||||
(osc .
|
|
||||||
[(0 1)
|
|
||||||
nil "Open Sound Control protocol library" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/osc.html")
|
|
||||||
(:keywords "comm" "processes" "multimedia"))])
|
|
||||||
(pabbrev .
|
|
||||||
[(4 2)
|
|
||||||
nil "Predictive abbreviation expansion" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/pabbrev.html")
|
|
||||||
(:keywords))])
|
|
||||||
(pinentry .
|
|
||||||
[(0 1)
|
|
||||||
nil "GnuPG Pinentry server implementation" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/pinentry.html")
|
|
||||||
(:keywords "gnupg"))])
|
|
||||||
(poker .
|
|
||||||
[(0 1)
|
|
||||||
nil "Texas hold'em poker" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/poker.html")
|
|
||||||
(:keywords "games"))])
|
|
||||||
(quarter-plane .
|
|
||||||
[(0 1)
|
|
||||||
nil "Minor mode for quarter-plane style editing" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/quarter-plane.html")
|
|
||||||
(:keywords "convenience" "wp"))])
|
|
||||||
(queue .
|
|
||||||
[(0 1 1)
|
|
||||||
nil "Queue data structure" single
|
|
||||||
((:url . "http://www.dr-qubit.org/emacs.php")
|
|
||||||
(:keywords "extensions" "data structures" "queue"))])
|
|
||||||
(rainbow-mode .
|
|
||||||
[(0 11)
|
|
||||||
nil "Colorize color names in buffers" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/rainbow-mode.html")
|
|
||||||
(:keywords "faces"))])
|
|
||||||
(register-list .
|
|
||||||
[(0 1)
|
|
||||||
nil "Interactively list/edit registers" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/register-list.html")
|
|
||||||
(:keywords "register"))])
|
|
||||||
(rudel .
|
|
||||||
[(0 3)
|
|
||||||
nil "A collaborative editing framework for Emacs" tar
|
|
||||||
((:keywords "rudel" "collaboration")
|
|
||||||
(:url . "http://rudel.sourceforge.net/"))])
|
|
||||||
(scroll-restore .
|
|
||||||
[(1 0)
|
|
||||||
nil "restore original position after scrolling" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/scroll-restore.html")
|
|
||||||
(:keywords "scrolling"))])
|
|
||||||
(seq .
|
|
||||||
[(1 7)
|
|
||||||
nil "Sequence manipulation functions" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/seq.html")
|
|
||||||
(:keywords "sequences"))])
|
|
||||||
(shen-mode .
|
|
||||||
[(0 1)
|
|
||||||
nil "A major mode for editing shen source code" tar
|
|
||||||
((:keywords "languages" "shen")
|
|
||||||
(:url . "http://elpa.gnu.org/packages/shen-mode.html"))])
|
|
||||||
(sisu-mode .
|
|
||||||
[(3 0 3)
|
|
||||||
nil "Major mode for SiSU markup text" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/sisu-mode.html")
|
|
||||||
(:keywords "text" "processes" "tools"))])
|
|
||||||
(sml-mode .
|
|
||||||
[(6 7)
|
|
||||||
nil "Major mode for editing (Standard) ML" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/sml-mode.html")
|
|
||||||
(:keywords "sml"))])
|
|
||||||
(sokoban .
|
|
||||||
[(1 4)
|
|
||||||
nil "Implementation of Sokoban for Emacs." tar
|
|
||||||
((:keywords "games")
|
|
||||||
(:url . "http://elpa.gnu.org/packages/sokoban.html"))])
|
|
||||||
(sotlisp .
|
|
||||||
[(1 0)
|
|
||||||
((emacs
|
|
||||||
(24 1)))
|
|
||||||
"Write lisp at the speed of thought." single
|
|
||||||
((:url . "https://github.com/Malabarba/speed-of-thought-lisp")
|
|
||||||
(:keywords "convenience" "lisp"))])
|
|
||||||
(spinner .
|
|
||||||
[(1 3 1)
|
|
||||||
nil "Add spinners and progress-bars to the mode-line for ongoing operations" single
|
|
||||||
((:url . "https://github.com/Malabarba/spinner.el")
|
|
||||||
(:keywords "processes" "mode-line"))])
|
|
||||||
(svg .
|
|
||||||
[(0 1)
|
|
||||||
((emacs
|
|
||||||
(25)))
|
|
||||||
"svg image creation functions" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/svg.html")
|
|
||||||
(:keywords "image"))])
|
|
||||||
(svg-clock .
|
|
||||||
[(0 5)
|
|
||||||
((svg
|
|
||||||
(0 1))
|
|
||||||
(emacs
|
|
||||||
(25 0)))
|
|
||||||
"Analog clock using Scalable Vector Graphics" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/svg-clock.html")
|
|
||||||
(:keywords "demo" "svg" "clock"))])
|
|
||||||
(swiper .
|
|
||||||
[(0 4 1)
|
|
||||||
((emacs
|
|
||||||
(24 1)))
|
|
||||||
"Isearch with an overview. Oh, man!" tar
|
|
||||||
((:keywords "matching")
|
|
||||||
(:url . "https://github.com/abo-abo/swiper"))])
|
|
||||||
(tNFA .
|
|
||||||
[(0 1 1)
|
|
||||||
((queue
|
|
||||||
(0 1)))
|
|
||||||
"Tagged non-deterministic finite-state automata" single
|
|
||||||
((:url . "http://www.dr-qubit.org/emacs.php")
|
|
||||||
(:keywords "extensions" "matching" "data structures tnfa" "nfa" "dfa" "finite state automata" "automata" "regexp"))])
|
|
||||||
(temp-buffer-browse .
|
|
||||||
[(1 4)
|
|
||||||
nil "temp buffer browse mode" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/temp-buffer-browse.html")
|
|
||||||
(:keywords "convenience"))])
|
|
||||||
(test-simple .
|
|
||||||
[(1 1)
|
|
||||||
((cl-lib
|
|
||||||
(0)))
|
|
||||||
"Simple Unit Test Framework for Emacs Lisp" single
|
|
||||||
((:url . "http://github.com/rocky/emacs-test-simple")
|
|
||||||
(:keywords "unit-test"))])
|
|
||||||
(timerfunctions .
|
|
||||||
[(1 4 2)
|
|
||||||
((cl-lib
|
|
||||||
(0 5)))
|
|
||||||
"Enhanced versions of some timer.el functions" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/timerfunctions.html")
|
|
||||||
(:keywords))])
|
|
||||||
(tiny .
|
|
||||||
[(0 1)
|
|
||||||
nil "Quickly generate linear ranges in Emacs" tar
|
|
||||||
((:keywords "convenience")
|
|
||||||
(:url . "https://github.com/abo-abo/tiny"))])
|
|
||||||
(trie .
|
|
||||||
[(0 2 6)
|
|
||||||
((tNFA
|
|
||||||
(0 1 1))
|
|
||||||
(heap
|
|
||||||
(0 3)))
|
|
||||||
"Trie data structure" single
|
|
||||||
((:url . "http://www.dr-qubit.org/emacs.php")
|
|
||||||
(:keywords "extensions" "matching" "data structures trie" "ternary search tree" "tree" "completion" "regexp"))])
|
|
||||||
(undo-tree .
|
|
||||||
[(0 6 5)
|
|
||||||
nil "Treat undo history as a tree" single
|
|
||||||
((:url . "http://www.dr-qubit.org/emacs.php")
|
|
||||||
(:keywords "convenience" "files" "undo" "redo" "history" "tree"))])
|
|
||||||
(uni-confusables .
|
|
||||||
[(0 1)
|
|
||||||
nil "Unicode confusables table" tar
|
|
||||||
((:url . "http://elpa.gnu.org/packages/uni-confusables.html"))])
|
|
||||||
(vlf .
|
|
||||||
[(1 7)
|
|
||||||
nil "View Large Files" tar
|
|
||||||
((:keywords "large files" "utilities")
|
|
||||||
(:url . "https://github.com/m00natic/vlfi"))])
|
|
||||||
(w3 .
|
|
||||||
[(4 0 49)
|
|
||||||
nil "Fully customizable, largely undocumented web browser for Emacs" tar
|
|
||||||
((:keywords "faces" "help" "comm" "news" "mail" "processes" "mouse" "hypermedia")
|
|
||||||
(:url . "http://elpa.gnu.org/packages/w3.html"))])
|
|
||||||
(wcheck-mode .
|
|
||||||
[(2014 6 21)
|
|
||||||
nil "General interface for text checkers" single
|
|
||||||
((:url . "https://github.com/tlikonen/wcheck-mode")
|
|
||||||
(:keywords "text" "spell" "check" "languages" "ispell"))])
|
|
||||||
(web-server .
|
|
||||||
[(0 1 1)
|
|
||||||
((emacs
|
|
||||||
(24 3)))
|
|
||||||
"Emacs Web Server" tar
|
|
||||||
((:keywords "http" "server" "network")
|
|
||||||
(:url . "https://github.com/eschulte/emacs-web-server"))])
|
|
||||||
(websocket .
|
|
||||||
[(1 4)
|
|
||||||
nil "Emacs WebSocket client and server" tar
|
|
||||||
((:keywords "communication" "websocket" "server")
|
|
||||||
(:url . "http://elpa.gnu.org/packages/websocket.html"))])
|
|
||||||
(windresize .
|
|
||||||
[(0 1)
|
|
||||||
nil "Resize windows interactively" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/windresize.html")
|
|
||||||
(:keywords "window"))])
|
|
||||||
(wisi .
|
|
||||||
[(1 1 1)
|
|
||||||
((cl-lib
|
|
||||||
(0 4))
|
|
||||||
(emacs
|
|
||||||
(24 2)))
|
|
||||||
"Utilities for implementing an indentation/navigation engine using a generalized LALR parser" tar
|
|
||||||
((:keywords "parser" "indentation" "navigation")
|
|
||||||
(:url . "http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html"))])
|
|
||||||
(wpuzzle .
|
|
||||||
[(1 1)
|
|
||||||
nil "find as many word in a given time" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/wpuzzle.html")
|
|
||||||
(:keywords))])
|
|
||||||
(xclip .
|
|
||||||
[(1 3)
|
|
||||||
nil "use xclip to copy&paste" single
|
|
||||||
((:url . "http://elpa.gnu.org/packages/xclip.html")
|
|
||||||
(:keywords "convenience" "tools"))])
|
|
||||||
(xpm .
|
|
||||||
[(1 0 3)
|
|
||||||
nil "edit XPM images" tar
|
|
||||||
((:keywords "multimedia" "xpm")
|
|
||||||
(:url . "http://www.gnuvola.org/software/xpm/"))])
|
|
||||||
(yasnippet .
|
|
||||||
[(0 8 0)
|
|
||||||
nil "Yet another snippet extension for Emacs." tar
|
|
||||||
((:keywords "convenience" "emulation")
|
|
||||||
(:url . "http://github.com/capitaomorte/yasnippet"))])
|
|
||||||
(ztree .
|
|
||||||
[(1 0 1)
|
|
||||||
nil "Text mode directory tree" tar
|
|
||||||
((:keywords "files" "tools")
|
|
||||||
(:url . "https://github.com/fourier/ztree"))]))
|
|
@@ -1 +0,0 @@
|
|||||||
Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent <elpasign@elpa.gnu.org> (trust undefined) created at 2015-06-12T11:05:02+0200 using DSA
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,26 +0,0 @@
|
|||||||
;;; clojure-mode-autoloads.el --- automatically extracted autoloads
|
|
||||||
;;
|
|
||||||
;;; Code:
|
|
||||||
(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
|
|
||||||
|
|
||||||
;;;### (autoloads nil "clojure-mode" "clojure-mode.el" (21860 25961
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from clojure-mode.el
|
|
||||||
|
|
||||||
(autoload 'clojure-mode "clojure-mode" "\
|
|
||||||
Major mode for editing Clojure code.
|
|
||||||
|
|
||||||
\\{clojure-mode-map}
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.\\(clj[sx]?\\|dtm\\|edn\\)\\'" . clojure-mode))
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; End:
|
|
||||||
;;; clojure-mode-autoloads.el ends here
|
|
@@ -1,11 +0,0 @@
|
|||||||
;;; clojure-mode-autoloads.el --- automatically extracted autoloads
|
|
||||||
;;
|
|
||||||
;;; Code:
|
|
||||||
(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; End:
|
|
||||||
;;; clojure-mode-autoloads.el ends here
|
|
@@ -1 +0,0 @@
|
|||||||
(define-package "clojure-mode" "4.0.1" "Major mode for Clojure code" '((emacs "24.1")) :url "http://github.com/clojure-emacs/clojure-mode" :keywords '("languages" "clojure" "clojurescript" "lisp"))
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,438 +0,0 @@
|
|||||||
Haskell Mode NEWS -*- org -*-
|
|
||||||
|
|
||||||
This file uses Org mode. Some useful (default) key-bindings:
|
|
||||||
- Use "C-c C-n"/"C-c C-p" to jump to next/prev heading
|
|
||||||
- Use "<tab>" to expand/collapse nodes
|
|
||||||
- Use "<backtab>" to cycle visibility of all nodes
|
|
||||||
- Use "C-c C-o" to open links
|
|
||||||
|
|
||||||
* Changes in 13.12
|
|
||||||
|
|
||||||
- Added haskell-bot.el
|
|
||||||
|
|
||||||
- Added support for cabal repl build targets
|
|
||||||
|
|
||||||
- Automatically add import lines via Hoogle
|
|
||||||
|
|
||||||
- Automatically add package to cabal file
|
|
||||||
|
|
||||||
- Added w3m-haddock.el
|
|
||||||
|
|
||||||
- Added debugger mode
|
|
||||||
|
|
||||||
- Added preliminary :present support
|
|
||||||
|
|
||||||
- Added haskell-sort-imports
|
|
||||||
|
|
||||||
- Added haskell-complete-module
|
|
||||||
|
|
||||||
- Support if and multi-way if in indentation
|
|
||||||
|
|
||||||
- Add support to generate tags on windows
|
|
||||||
|
|
||||||
- Add haskell-language-extensions variable
|
|
||||||
|
|
||||||
- Improve haskell-simple-indent mode
|
|
||||||
|
|
||||||
- Improve test cases
|
|
||||||
|
|
||||||
* Changes in 13.10
|
|
||||||
|
|
||||||
- Small fix for haskell-simple-indent: Certain indentation situations
|
|
||||||
cause valname-string to be nil, which haskell-trim did not handle
|
|
||||||
gracefully (naturally, since nil != "").
|
|
||||||
|
|
||||||
- Luke Hoersten's Shnippet merged in under snippets/.
|
|
||||||
|
|
||||||
- haskell-presentation-mode is now a haskell-mode derived mode.
|
|
||||||
|
|
||||||
- Small improvement to haskell-process-do-info (works on constructors
|
|
||||||
now and underscored names).
|
|
||||||
|
|
||||||
- Add haskell-indent-spaces configuration variable.
|
|
||||||
|
|
||||||
- The command string to run cabal commands is slightly more
|
|
||||||
configurable. See: C-h f haskell-process-do-cabal-format-string
|
|
||||||
|
|
||||||
* Changes in 13.8
|
|
||||||
|
|
||||||
See also [[https://github.com/haskell/haskell-mode/compare/v13.07...v13.08][detailed Git history]].
|
|
||||||
|
|
||||||
- Make `haskell-simple-indent-mode' a proper minor mode with `SInd` as
|
|
||||||
mode-line lighter
|
|
||||||
|
|
||||||
- Support popular "λ> " prompt in inf-haskell by default
|
|
||||||
|
|
||||||
- Hide internal `*print-haskell-mode*' buffers
|
|
||||||
(used when `haskell-interactive-mode-eval-mode' is active)
|
|
||||||
|
|
||||||
- Add tab-completion support for haskell-interactive-mode
|
|
||||||
(requires `:complete' command support in GHCi)
|
|
||||||
|
|
||||||
- Add support to `haskell-process-do-info` to perform `:browse!` query
|
|
||||||
on module name when called on import statement line
|
|
||||||
|
|
||||||
- `haskell-decl-scan-mode':
|
|
||||||
- New customize group `haskell-decl-scan'
|
|
||||||
- New flag `haskell-decl-scan-bindings-as-variables' for controlling
|
|
||||||
whether to put value bindings into the "Variables" category.
|
|
||||||
- New flag `haskell-decl-scan-add-to-menubar' for controlling
|
|
||||||
whether to add "Declarations" menu entry to menu bar.
|
|
||||||
- New manual section node `(haskell-mode)haskell-decl-scan-mode'
|
|
||||||
|
|
||||||
- Add support for [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#lambda-case][LambdaCase]] syntax extension to `haskell-indentation`
|
|
||||||
|
|
||||||
- Change `haskell-indentation-mode' to never jump back a whole line
|
|
||||||
when pressing DEL. The old behavior can be restored by setting
|
|
||||||
`haskell-indentation-delete-backward-jump-line' to t
|
|
||||||
|
|
||||||
- New convenience function `haskell-cabal-visit-file' for locating and
|
|
||||||
visiting most likely `.cabal` file associated with current buffer
|
|
||||||
|
|
||||||
- Add support for [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#package-import][PackageImports]] and [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#safe-imports-ext][SafeHaskell]] syntax extensions to
|
|
||||||
`haskell-decl-scan-mode' parser
|
|
||||||
|
|
||||||
- Add `turn-{on,off}-haskell-doc' commands as aliases for the existing
|
|
||||||
`turn-{on,off}-haskell-doc-mode' commands
|
|
||||||
|
|
||||||
- Add support for "cabal repl" process type to `haskell-interactive-mode'
|
|
||||||
|
|
||||||
- Add new Haskell compilation sub-mode and associated `haskell-compile'
|
|
||||||
command
|
|
||||||
|
|
||||||
* Changes in 13.7
|
|
||||||
|
|
||||||
See also [[https://github.com/haskell/haskell-mode/compare/v13.06...v13.07][detailed Git history]].
|
|
||||||
|
|
||||||
- Convert NEWS (this file) to Org mode style and include NEWS file in
|
|
||||||
package and add command for visiting NEWS file
|
|
||||||
(M-x haskell-mode-view-news)
|
|
||||||
|
|
||||||
- Officially drop support for versions prior to Emacs 23
|
|
||||||
|
|
||||||
- New work-in-progress Info manual for haskell-mode
|
|
||||||
|
|
||||||
- Remove deprecated `haskell-{hugs,ghci}' modules
|
|
||||||
|
|
||||||
- Font-locking changes:
|
|
||||||
- Remove deprecated `turn-on-haskell-font-lock` function
|
|
||||||
- Improve font-locking of type-signatures in presence of newlines
|
|
||||||
- Use `font-lock-preprocessor-face' instead of the previously used
|
|
||||||
`font-lock-warning-face` for CPP directives
|
|
||||||
- Use `font-lock-warning-face` instead of the previously used
|
|
||||||
`font-lock-preprocessor-face` for Git merge conflict annotations.
|
|
||||||
|
|
||||||
- Improvements to `haskell-move-nested' module:
|
|
||||||
- Add support for operating on active regions
|
|
||||||
- New interactive commands `haskell-move-nested-{left,right}` which
|
|
||||||
support numeric prefix arguments for controlling the amount of
|
|
||||||
shifting to apply.
|
|
||||||
|
|
||||||
- Add `haskell-unicode-input-method.el` to distribution
|
|
||||||
(enable with `turn-on-haskell-unicode-input-method`)
|
|
||||||
|
|
||||||
- Fix all byte-compilation warnings
|
|
||||||
|
|
||||||
- Build-system:
|
|
||||||
- For in-place installation, `haskell-site-file.el' is renamed
|
|
||||||
to `haskell-mode-autoloads.el`
|
|
||||||
- Auto-generate ELPA compatible README file by extracting header of
|
|
||||||
haskell-mode.el
|
|
||||||
- New "make check" target
|
|
||||||
- Add Travis-CI build jobs for testing byte-compilation with
|
|
||||||
multiple Emacs versions
|
|
||||||
|
|
||||||
- Reorganize customize settings
|
|
||||||
- Add new convenience function for browsing all Haskell Mode settings
|
|
||||||
(M-x haskell-customize)
|
|
||||||
- Add `:link' keywords pointing to the new Info manual
|
|
||||||
- Add `:group' keywords to modes to make (M-x customize-mode) work
|
|
||||||
- Create new customization groups `haskell-interactive' and `inferior-haskell'
|
|
||||||
to clean up namespace
|
|
||||||
- Create new customization group `ghc-core` containing the two new
|
|
||||||
customization variables `ghc-core-program` and `ghc-core-program-args`.
|
|
||||||
|
|
||||||
- Improvements to haskell-interactive-mode
|
|
||||||
- Add support for deleting compile messages superseded by recompile/reloads
|
|
||||||
(M-x customize-variable RET haskell-interactive-mode-delete-superseded-errors)
|
|
||||||
- Fix `C-u M-x haskell-process-do-type` inserting bad signatures
|
|
||||||
- Integrate with Emacs' `next-error` subsystem
|
|
||||||
- Add "C-c C-f" binding to REPL keymap for enabling `next-error-follow-minor-mode'
|
|
||||||
- Add support for `-ferror-spans`-style compile messages
|
|
||||||
- Add `-ferror-spans` as default for `haskell-process-args-ghci`
|
|
||||||
- Add optional argument to
|
|
||||||
`haskell-session-{all,installed,project}-modules' to suppress
|
|
||||||
session-creation. This is useful for yasnippet usage, see commit
|
|
||||||
517fd7e for an example.
|
|
||||||
- Change default for `haskell-process-path-ghci` to a static "ghci"
|
|
||||||
- Fix `haskell-interactive-switch` not selecting the REPL window
|
|
||||||
- Make `*haskell-process-log*` buffer configurable
|
|
||||||
(controlled via new `haskell-process-log` customize option)
|
|
||||||
|
|
||||||
* Changes in 13.6
|
|
||||||
|
|
||||||
See also [[https://github.com/haskell/haskell-mode/compare/2_9_1...v13.06][detailed Git history]].
|
|
||||||
|
|
||||||
- Switch to new versioning scheme
|
|
||||||
|
|
||||||
- Switch to MELPA/Marmalade based packaging
|
|
||||||
|
|
||||||
- Cleanup/refactor build-system
|
|
||||||
|
|
||||||
- Enhance `M-x haskell-version` to report more detailed versioning
|
|
||||||
information
|
|
||||||
|
|
||||||
- Make haskell-interactive-mode emulate comint/eshell history navigation
|
|
||||||
(see commit 0e96843 for more details)
|
|
||||||
|
|
||||||
- Improvements to haskell-interactive-mode
|
|
||||||
- Improve killing/restarting haskell-interactive sessions
|
|
||||||
- Improve directory prompting and resolution
|
|
||||||
- Fix redundant-import suggest trigger to support qualified imports
|
|
||||||
- Detect all abbreviations of an user-inputted ":quit"
|
|
||||||
- Fix regexps for recent GHC 7.x compiler messages
|
|
||||||
- Customizable commandline args for GHCi
|
|
||||||
(M-x customize-variable RET haskell-process-args-ghci)
|
|
||||||
- New command to load or reload via prefix argument
|
|
||||||
(M-x haskell-process-load-or-reload)
|
|
||||||
- Fix haskell-interactive-mode prompt detection
|
|
||||||
- Add cabal-ghci as supported process mode
|
|
||||||
- Add a customization option for the visibility of multi-line errors
|
|
||||||
(M-x customize-variable RET haskell-interactive-mode-hide-multi-line-errors)
|
|
||||||
|
|
||||||
- Add forward declarations to reduce Elisp bytecompile warnings
|
|
||||||
|
|
||||||
- Improvements to `haskell-indentation`
|
|
||||||
- Add support for the UnicodeSyntax tokens `→`, `←`, and `∷`.
|
|
||||||
- Indent "=" following data/type/newtype declarations.
|
|
||||||
- Align "->"/"→" arrows in types under "::"/"∷"
|
|
||||||
- Make customizable whether "<backspace>" deletes indentation too
|
|
||||||
(via `haskell-indentation-delete-backward-indentation` and
|
|
||||||
`haskell-indentation-delete-indentation`)
|
|
||||||
- Properly indent 'rec' keyword, same as 'mdo'
|
|
||||||
- Minor optimizations.
|
|
||||||
|
|
||||||
- Add support for "'"-prefixed constructors (-> DataKinds) to font-locking
|
|
||||||
|
|
||||||
- New experimental haskell session menu mode (M-x haskell-menu)
|
|
||||||
|
|
||||||
- Various minor cleanups/fixes/improvements...
|
|
||||||
|
|
||||||
* Changes in 2.9.1
|
|
||||||
|
|
||||||
See also [[https://github.com/haskell/haskell-mode/compare/2_9_0...2_9_1][detailed Git history]].
|
|
||||||
|
|
||||||
- Bugfix release adding missing autoload declaration
|
|
||||||
|
|
||||||
* Changes in 2.9.0
|
|
||||||
|
|
||||||
See also [[https://github.com/haskell/haskell-mode/compare/2_8_0...2_9_0][detailed Git history]].
|
|
||||||
|
|
||||||
- This is the first release after haskell-mode was migrated to GitHub
|
|
||||||
|
|
||||||
- New experimental `haskell-interactive-mode' module implementing a
|
|
||||||
new REPL interaction mode for GHCi sessions to eventually replace
|
|
||||||
the existing "inf-haskell" mode.
|
|
||||||
|
|
||||||
- New `haskell-process-cabal' command for interaction with cabal-install
|
|
||||||
|
|
||||||
- New `haskell-checkers' module
|
|
||||||
|
|
||||||
- Update haskell-cabal-mode font-lock keywords
|
|
||||||
|
|
||||||
- Improve scrolling of hoogle output (haskell-mode.el)
|
|
||||||
|
|
||||||
- Derive `haskell-mode` from `prog-mode` for Emacs 24+
|
|
||||||
|
|
||||||
- Add new binding for "<backtab>" to haskell-mode's keymap which
|
|
||||||
unindents current line
|
|
||||||
|
|
||||||
- New modules `haskell-navigate-imports`, `haskell-sort-imports' and
|
|
||||||
`haskell-align-imports' for operating on module import lines in
|
|
||||||
Haskell source code
|
|
||||||
|
|
||||||
- Add new binding for "C-c C-." to haskell-mode's keymap to sort and
|
|
||||||
realign Haskell module imports
|
|
||||||
|
|
||||||
- Add new binding for "C-c i" to haskell-mode's keymap to jump back and
|
|
||||||
forth from/to the current Haskell module's module import section.
|
|
||||||
|
|
||||||
- New `inferior-haskell-kind' function for querying kind via GHCi's ":kind"
|
|
||||||
|
|
||||||
- New `inferior-haskell-send-decl' for sending declarations to GHCi
|
|
||||||
(bound to "C-x C-d" by default)
|
|
||||||
|
|
||||||
- Add new `haskell-doc-use-inf-haskell` customization variable
|
|
||||||
|
|
||||||
- Add support for bird-style literate haskell editing and a new
|
|
||||||
related customization variable
|
|
||||||
`haskell-indentation-birdtrack-extra-space'
|
|
||||||
|
|
||||||
- Font locking improvements
|
|
||||||
- Add support for Git's merge annotation
|
|
||||||
(with `font-lock-preprocessor-face')
|
|
||||||
- Improve `import', `foreign import' and `foreign export' font
|
|
||||||
locking
|
|
||||||
- Add support for `rec', `proc' and `mdo` as keywords
|
|
||||||
- Make whitespace within `-- |' and `{- |' optional when possible
|
|
||||||
|
|
||||||
- New `haskell-move-nested` module providing utilities for
|
|
||||||
interactively {in,de}denting nested "hanging" blocks.
|
|
||||||
|
|
||||||
- Add stylish-haskell support
|
|
||||||
(enable via `haskell-stylish-on-save` customization variable)
|
|
||||||
|
|
||||||
- Add support for generating tags on save
|
|
||||||
(enable via `haskell-tags-on-save' customization variable)
|
|
||||||
|
|
||||||
- Set sensible dabbrev defaults in haskell-mode
|
|
||||||
|
|
||||||
- Added `SCC` pragma insert/delete commands
|
|
||||||
(`haskell-mode-insert-scc-at-point` and `haskell-mode-kill-scc-at-point')
|
|
||||||
|
|
||||||
- New experimental `haskell-mode-contextual-space' command
|
|
||||||
|
|
||||||
- And a couple more cleanups/fixes/improvements...
|
|
||||||
|
|
||||||
* Changes in 2.8.0 (since 2.7.0)
|
|
||||||
|
|
||||||
See also [[https://github.com/haskell/haskell-mode/compare/2_7_0...2_8_0][detailed Git history]].
|
|
||||||
|
|
||||||
- Minimal indentation support for arrow syntax
|
|
||||||
|
|
||||||
- Avoid opening a new inf-haskell window if one is already visible.
|
|
||||||
Windows on other virtual desktops or iconified frames don't count.
|
|
||||||
|
|
||||||
- Force comint-process-echoes to nil
|
|
||||||
|
|
||||||
- Autolaunch haskell-mode for files starting with #!/usr/bin/runghc
|
|
||||||
and similar
|
|
||||||
|
|
||||||
- Added minimal major mode for parsing GHC core files, courtesy of Johan Tibell.
|
|
||||||
There is a corresponding Haskell menu entry.
|
|
||||||
|
|
||||||
- Allow configuration of where-clause indentation; M-x customize-group
|
|
||||||
haskell-indentation.
|
|
||||||
|
|
||||||
* Changes since 2.6.4
|
|
||||||
|
|
||||||
- fill-paragraph (M-q) now only affects comments, and correctly
|
|
||||||
handles Haddock commentary. adaptive-fill-mode is turned off, as it
|
|
||||||
was interfering.
|
|
||||||
|
|
||||||
- Yet more unicode symbols
|
|
||||||
|
|
||||||
- Better support for unicode encoding of haskell source files
|
|
||||||
|
|
||||||
- mdo correctly indented
|
|
||||||
|
|
||||||
- Indentation fixes, fixes to the fixes, and fixes to the fixes to the
|
|
||||||
fixes
|
|
||||||
|
|
||||||
- New command: M-x haskell-check, calls (by default) hlint on the
|
|
||||||
current file. Also bound to C-c C-v.
|
|
||||||
|
|
||||||
You can also use the flymake minor mode with this.
|
|
||||||
|
|
||||||
* Changes since 2.5.1
|
|
||||||
|
|
||||||
- Parser corrections for haskell-indentation and haskell-decl-scan
|
|
||||||
|
|
||||||
- haskell-indentation: Pressing tab in the rightmost position now
|
|
||||||
moves to the leftmost, by default with a warning.
|
|
||||||
|
|
||||||
- Typo fix: One haskell-indentation variable had ended up in the
|
|
||||||
haskell-ntation customize group.
|
|
||||||
|
|
||||||
- haskell-hoogle aliased to hoogle, haskell-hayoo aliased to hayoo
|
|
||||||
|
|
||||||
- Courtesy of Alex Ott:
|
|
||||||
- Additional unicode symbols for font-lock-symbols: () == /= >= <= !! && || sqrt
|
|
||||||
- M-x haskell-hayoo search added, opens using browse-url
|
|
||||||
- Bug-fix for inferior-haskell-type
|
|
||||||
|
|
||||||
- If haskell-indentation errors out, it now fail-safes to inserting
|
|
||||||
a literal newline or deleting one character, for return and
|
|
||||||
backspace respectively.
|
|
||||||
|
|
||||||
* Changes since 2.4:
|
|
||||||
|
|
||||||
- haskell-indentation, a new minor mode for indentation.
|
|
||||||
|
|
||||||
* Changes since 2.3:
|
|
||||||
|
|
||||||
- Update license to GPLv3.
|
|
||||||
|
|
||||||
- New derived major mode for .hsc files.
|
|
||||||
|
|
||||||
- Removed the C-c C-r binding to reload a file. You can still call
|
|
||||||
inferior-haskell-reload-file (and/or bind it to your favorite key,
|
|
||||||
including C-c C-r) or you can now use C-u C-c C-l.
|
|
||||||
|
|
||||||
- C-c C-d looks up the symbol at point in the Haddock docs.
|
|
||||||
|
|
||||||
- Haddock comments are highlighted with font-lock-doc-face if it exists.
|
|
||||||
|
|
||||||
- Use `tex' rather than `latex' for haskell-literate.
|
|
||||||
|
|
||||||
- inf-haskell.el tries to find the root of the module hierarchy to determine
|
|
||||||
the root of a project (either by looking for a Cabal file or relying on
|
|
||||||
the `module' declaration line). If all works well, this will make C-c C-l
|
|
||||||
automatically switch to the root dir, so that dependencies in other
|
|
||||||
directories are automatically found. If it doesn't, complain and/or set
|
|
||||||
inferior-haskell-find-project-root to nil.
|
|
||||||
|
|
||||||
- The new command haskell-hoogle helps you query Hoogle from Emacs.
|
|
||||||
|
|
||||||
* Changes since 2.2:
|
|
||||||
|
|
||||||
- Trivial support for Cabal package description files.
|
|
||||||
|
|
||||||
- Minor bug fixes.
|
|
||||||
|
|
||||||
* Changes since 2.1:
|
|
||||||
|
|
||||||
- There are now commands to find type and info of identifiers by querying an
|
|
||||||
inferior haskell process. Available under C-c C-t, C-c C-i, and C-c M-.
|
|
||||||
|
|
||||||
- Indentation now looks back further, until a line that has no indentation.
|
|
||||||
To recover the earlier behavior of stopping at the first empty line
|
|
||||||
instead, configure haskell-indent-look-past-empty-line.
|
|
||||||
|
|
||||||
- inf-haskell can wait until a file load completes and jump directly to the
|
|
||||||
first error, like haskell-ghci and haskell-hugs used to do. See the var
|
|
||||||
inferior-haskell-wait-and-jump.
|
|
||||||
|
|
||||||
* Changes since 2.0:
|
|
||||||
|
|
||||||
- inf-haskell uses ghci if hugs is absent.
|
|
||||||
|
|
||||||
- Fix up some binding conflicts (C-c C-o in haskell-doc)
|
|
||||||
|
|
||||||
- Many (hopefully minor) changes to the indentation.
|
|
||||||
|
|
||||||
- New symbols in haskell-font-lock-symbols-alist.
|
|
||||||
|
|
||||||
* Changes since 1.45:
|
|
||||||
|
|
||||||
- keybindings C-c <char> have been replaced by C-c C-<char> so as not
|
|
||||||
to collide with minor modes.
|
|
||||||
|
|
||||||
- The following modules are now automatically activated without having to
|
|
||||||
add anything to haskell-mode-hook:
|
|
||||||
haskell-font-lock (just turn on global-font-lock-mode).
|
|
||||||
haskell-decl-scan (just bind `imenu' to some key).
|
|
||||||
|
|
||||||
- In recent Emacsen, haskell-doc hooks into eldoc-mode.
|
|
||||||
|
|
||||||
- haskell-hugs and haskell-ghci are superceded by inf-haskell.
|
|
||||||
|
|
||||||
- Indentation rules have been improved when using layout inside parens/braces.
|
|
||||||
|
|
||||||
- Symbols like -> and \ can be displayed as actual arrows and lambdas.
|
|
||||||
See haskell-font-lock-symbols.
|
|
||||||
|
|
||||||
- Tweaks to the font-lock settings. Among other things paren-matching
|
|
||||||
with things like \(x,y) should work correctly now.
|
|
||||||
|
|
||||||
- New maintainer <monnier@gnu.org>.
|
|
@@ -1,18 +0,0 @@
|
|||||||
This is the file .../info/dir, which contains the
|
|
||||||
topmost node of the Info hierarchy, called (dir)Top.
|
|
||||||
The first time you invoke Info you start off looking at this node.
|
|
||||||
|
|
||||||
File: dir, Node: Top This is the top of the INFO tree
|
|
||||||
|
|
||||||
This (the Directory node) gives a menu of major topics.
|
|
||||||
Typing "q" exits, "?" lists all Info commands, "d" returns here,
|
|
||||||
"h" gives a primer for first-timers,
|
|
||||||
"mEmacs<Return>" visits the Emacs manual, etc.
|
|
||||||
|
|
||||||
In Emacs, you can click mouse button 2 on a menu item or cross reference
|
|
||||||
to select it.
|
|
||||||
|
|
||||||
* Menu:
|
|
||||||
|
|
||||||
Emacs
|
|
||||||
* Haskell Mode: (haskell-mode). Haskell Development Environment for Emacs(en)
|
|
@@ -1,122 +0,0 @@
|
|||||||
;;; ghc-core.el --- Syntax highlighting module for GHC Core
|
|
||||||
|
|
||||||
;; Copyright (C) 2010 Johan Tibell
|
|
||||||
|
|
||||||
;; Author: Johan Tibell <johan.tibell@gmail.com>
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 GNU Emacs; see the file COPYING. If not, write to
|
|
||||||
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
||||||
;; Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Purpose:
|
|
||||||
;;
|
|
||||||
;; To make it easier to read GHC Core output by providing highlighting
|
|
||||||
;; and removal of commonly ignored annotations.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
(require 'haskell-mode)
|
|
||||||
(require 'haskell-font-lock)
|
|
||||||
|
|
||||||
(defgroup ghc-core nil
|
|
||||||
"Major mode for viewing pretty printed GHC Core output."
|
|
||||||
:link '(custom-manual "(haskell-mode)")
|
|
||||||
:group 'haskell
|
|
||||||
:prefix "ghc-core-")
|
|
||||||
|
|
||||||
(defcustom ghc-core-program
|
|
||||||
"ghc"
|
|
||||||
"Name of the GHC executable (excluding any arguments)."
|
|
||||||
:type 'string
|
|
||||||
:group 'ghc-core)
|
|
||||||
|
|
||||||
(defcustom ghc-core-program-args
|
|
||||||
'("-O2")
|
|
||||||
"Additional options to be passed to GHC when generating core output.
|
|
||||||
GHC (see variable `ghc-core-program') is invoked with the basic
|
|
||||||
command line options \"-ddump-simpl -c <source-file>\"
|
|
||||||
followed by the additional options defined here.
|
|
||||||
|
|
||||||
The following `-ddump-simpl` options might be of interest:
|
|
||||||
|
|
||||||
- `-dsuppress-all'
|
|
||||||
- `-dsuppress-uniques'
|
|
||||||
- `-dsuppress-idinfo'
|
|
||||||
- `-dsuppress-module-prefixes'
|
|
||||||
- `-dsuppress-type-signatures'
|
|
||||||
- `-dsuppress-type-applications'
|
|
||||||
- `-dsuppress-coercions'
|
|
||||||
|
|
||||||
See `M-x manual-entry RET ghc' for more details."
|
|
||||||
:type '(repeat (string :tag "Argument"))
|
|
||||||
:group 'ghc-core)
|
|
||||||
|
|
||||||
(define-obsolete-variable-alias 'ghc-core-create-options 'ghc-core-program-args
|
|
||||||
"haskell-mode 13.7")
|
|
||||||
|
|
||||||
(defun ghc-core-clean-region (start end)
|
|
||||||
"Remove commonly ignored annotations and namespace prefixes
|
|
||||||
in the region between START and END."
|
|
||||||
(interactive "r")
|
|
||||||
(save-restriction
|
|
||||||
(narrow-to-region start end)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (search-forward-regexp "GHC\.[^\.]*\." nil t)
|
|
||||||
(replace-match "" nil t))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (flush-lines "^ *GblId *$" nil))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (flush-lines "^ *LclId *$" nil))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (flush-lines (concat "^ *\\[\\(?:Arity [0-9]+\\|NoCafRefs\\|"
|
|
||||||
"Str: DmdType\\|Worker \\)"
|
|
||||||
"\\([^]]*\\n?\\).*\\] *$") nil))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (search-forward "Main." nil t) (replace-match "" nil t))))
|
|
||||||
|
|
||||||
(defun ghc-core-clean-buffer ()
|
|
||||||
"Remove commonly ignored annotations and namespace prefixes
|
|
||||||
in the current buffer."
|
|
||||||
(interactive)
|
|
||||||
(ghc-core-clean-region (point-min) (point-max)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun ghc-core-create-core ()
|
|
||||||
"Compile and load the current buffer as tidy core."
|
|
||||||
(interactive)
|
|
||||||
(save-buffer)
|
|
||||||
(let* ((core-buffer (generate-new-buffer "ghc-core"))
|
|
||||||
(neh (lambda () (kill-buffer core-buffer))))
|
|
||||||
(add-hook 'next-error-hook neh)
|
|
||||||
(apply #'call-process ghc-core-program nil core-buffer nil
|
|
||||||
"-ddump-simpl" "-c" (buffer-file-name) ghc-core-program-args)
|
|
||||||
(display-buffer core-buffer)
|
|
||||||
(with-current-buffer core-buffer
|
|
||||||
(ghc-core-mode))
|
|
||||||
(remove-hook 'next-error-hook neh)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.hcr\\'" . ghc-core-mode))
|
|
||||||
;;;###autoload
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.dump-simpl\\'" . ghc-core-mode))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-derived-mode ghc-core-mode haskell-mode "GHC-Core"
|
|
||||||
"Major mode for GHC Core files.")
|
|
||||||
|
|
||||||
(provide 'ghc-core)
|
|
||||||
;;; ghc-core.el ends here
|
|
Binary file not shown.
@@ -1,68 +0,0 @@
|
|||||||
;;; ghci-script-mode.el --- GHCi scripts major mode
|
|
||||||
|
|
||||||
;; Copyright (c) 2014 Chris Done. All rights reserved.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'haskell)
|
|
||||||
|
|
||||||
(defvar ghci-script-mode-keywords
|
|
||||||
;; The comment syntax can't be described simply in syntax-table.
|
|
||||||
;; We could use font-lock-syntactic-keywords, but is it worth it?
|
|
||||||
'(("^[ \t]*--.*" . font-lock-comment-face)
|
|
||||||
("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face))
|
|
||||||
("^:[a-z{]+ *\\+" . font-lock-keyword-face)
|
|
||||||
("^:[a-z{]+ " . font-lock-keyword-face)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-derived-mode ghci-script-mode text-mode "GHCi-Script"
|
|
||||||
"Major mode for working with .ghci files."
|
|
||||||
(set (make-local-variable 'adaptive-fill-mode) nil)
|
|
||||||
(set (make-local-variable 'comment-start) "-- ")
|
|
||||||
(set (make-local-variable 'comment-padding) 0)
|
|
||||||
(set (make-local-variable 'comment-start-skip) "[-{]-[ \t]*")
|
|
||||||
(set (make-local-variable 'comment-end) "")
|
|
||||||
(set (make-local-variable 'comment-end-skip) "[ \t]*\\(-}\\|\\s>\\)")
|
|
||||||
(set (make-local-variable 'indent-line-function) 'haskell-mode-suggest-indent-choice)
|
|
||||||
(set (make-local-variable 'font-lock-defaults)
|
|
||||||
'(ghci-script-mode-keywords t t nil nil))
|
|
||||||
(set (make-local-variable 'indent-tabs-mode) nil)
|
|
||||||
(set (make-local-variable 'tab-width) 8)
|
|
||||||
(when (boundp 'electric-indent-inhibit)
|
|
||||||
(setq electric-indent-inhibit t))
|
|
||||||
(set (make-local-variable 'dabbrev-case-fold-search) nil)
|
|
||||||
(set (make-local-variable 'dabbrev-case-distinction) nil)
|
|
||||||
(set (make-local-variable 'dabbrev-case-replace) nil)
|
|
||||||
(set (make-local-variable 'dabbrev-abbrev-char-regexp) "\\sw\\|[.]")
|
|
||||||
(setq haskell-literate nil))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.ghci\\'" . ghci-script-mode))
|
|
||||||
|
|
||||||
(define-key ghci-script-mode-map (kbd "C-c C-l") 'ghci-script-mode-load)
|
|
||||||
|
|
||||||
(defun ghci-script-mode-load ()
|
|
||||||
(interactive)
|
|
||||||
"Load the current script file into the GHCi session."
|
|
||||||
(let ((buffer (haskell-session-interactive-buffer (haskell-session)))
|
|
||||||
(filename (buffer-file-name)))
|
|
||||||
(save-buffer)
|
|
||||||
(with-current-buffer buffer
|
|
||||||
(set-marker haskell-interactive-mode-prompt-start (point-max))
|
|
||||||
(haskell-interactive-mode-run-expr
|
|
||||||
(concat ":script " filename)))))
|
|
||||||
|
|
||||||
(provide 'ghci-script-mode)
|
|
Binary file not shown.
@@ -1,230 +0,0 @@
|
|||||||
;;; haskell-align-imports.el --- Align the import lines in a Haskell file
|
|
||||||
|
|
||||||
;; Copyright (C) 2010 Chris Done
|
|
||||||
|
|
||||||
;; Author: Chris Done <chrisdone@gmail.com>
|
|
||||||
|
|
||||||
;; 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
|
|
||||||
;; <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Consider the following imports list:
|
|
||||||
;;
|
|
||||||
;; import One
|
|
||||||
;; import Two as A
|
|
||||||
;; import qualified Three
|
|
||||||
;; import qualified Four as PRELUDE
|
|
||||||
;; import Five (A)
|
|
||||||
;; import Six (A,B)
|
|
||||||
;; import qualified Seven (A,B)
|
|
||||||
;; import "abc" Eight
|
|
||||||
;; import "abc" Nine as TWO
|
|
||||||
;; import qualified "abc" Ten
|
|
||||||
;; import qualified "defg" Eleven as PRELUDE
|
|
||||||
;; import "barmu" Twelve (A)
|
|
||||||
;; import "zotconpop" Thirteen (A,B)
|
|
||||||
;; import qualified "z" Fourteen (A,B)
|
|
||||||
;; import Fifteen hiding (A)
|
|
||||||
;; import Sixteen as TWO hiding (A)
|
|
||||||
;; import qualified Seventeen hiding (A)
|
|
||||||
;; import qualified Eighteen as PRELUDE hiding (A)
|
|
||||||
;; import "abc" Nineteen hiding (A)
|
|
||||||
;; import "abc" Twenty as TWO hiding (A)
|
|
||||||
;;
|
|
||||||
;; When haskell-align-imports is run within the same buffer, the
|
|
||||||
;; import list is transformed to:
|
|
||||||
;;
|
|
||||||
;; import "abc" Eight
|
|
||||||
;; import qualified Eighteen as PRELUDE hiding (A)
|
|
||||||
;; import qualified "defg" Eleven as PRELUDE
|
|
||||||
;; import Fifteen hiding (A)
|
|
||||||
;; import Five (A)
|
|
||||||
;; import qualified Four as PRELUDE
|
|
||||||
;; import qualified "z" Fourteen (A,B)
|
|
||||||
;; import "abc" Nine as TWO
|
|
||||||
;; import "abc" Nineteen hiding (A)
|
|
||||||
;; import One
|
|
||||||
;; import qualified Seven (A,B)
|
|
||||||
;; import qualified Seventeen hiding (A)
|
|
||||||
;; import Six (A,B)
|
|
||||||
;; import Sixteen as TWO hiding (A)
|
|
||||||
;; import qualified "abc" Ten
|
|
||||||
;; import "zotconpop" Thirteen (A,B)
|
|
||||||
;; import qualified Three
|
|
||||||
;; import "barmu" Twelve (A)
|
|
||||||
;; import "abc" Twenty as TWO hiding (A)
|
|
||||||
;; import Two as A
|
|
||||||
;;
|
|
||||||
;; If you want everything after module names to be padded out, too,
|
|
||||||
;; customize `haskell-align-imports-pad-after-name', and you'll get:
|
|
||||||
;;
|
|
||||||
;; import One
|
|
||||||
;; import Two as A
|
|
||||||
;; import qualified Three
|
|
||||||
;; import qualified Four as PRELUDE
|
|
||||||
;; import Five (A)
|
|
||||||
;; import Six (A,B)
|
|
||||||
;; import qualified Seven (A,B)
|
|
||||||
;; import "abc" Eight
|
|
||||||
;; import "abc" Nine as TWO
|
|
||||||
;; import qualified "abc" Ten
|
|
||||||
;; import qualified "defg" Eleven as PRELUDE
|
|
||||||
;; import "barmu" Twelve (A)
|
|
||||||
;; import "zotconpop" Thirteen (A,B)
|
|
||||||
;; import qualified "z" Fourteen (A,B)
|
|
||||||
;; import Fifteen hiding (A)
|
|
||||||
;; import Sixteen as TWO hiding (A)
|
|
||||||
;; import qualified Seventeen hiding (A)
|
|
||||||
;; import qualified Eighteen as PRELUDE hiding (A)
|
|
||||||
;; import "abc" Nineteen hiding (A)
|
|
||||||
;; import "abc" Twenty as TWO hiding (A)
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
|
|
||||||
(defvar haskell-align-imports-regexp
|
|
||||||
(concat "^\\(import[ ]+\\)"
|
|
||||||
"\\(qualified \\)?"
|
|
||||||
"[ ]*\\(\"[^\"]*\" \\)?"
|
|
||||||
"[ ]*\\([A-Za-z0-9_.']+\\)"
|
|
||||||
"[ ]*\\([ ]*as [A-Z][^ ]*\\)?"
|
|
||||||
"[ ]*\\((.*)\\)?"
|
|
||||||
"\\([ ]*hiding (.*)\\)?"
|
|
||||||
"\\( -- .*\\)?[ ]*$")
|
|
||||||
"Regex used for matching components of an import.")
|
|
||||||
|
|
||||||
(defcustom haskell-align-imports-pad-after-name
|
|
||||||
nil
|
|
||||||
"Pad layout after the module name also."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-align-imports ()
|
|
||||||
"Align all the imports in the buffer."
|
|
||||||
(interactive)
|
|
||||||
(when (haskell-align-imports-line-match)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(let* ((imports (haskell-align-imports-collect))
|
|
||||||
(padding (haskell-align-imports-padding imports)))
|
|
||||||
(mapc (lambda (x)
|
|
||||||
(goto-char (cdr x))
|
|
||||||
(delete-region (point) (line-end-position))
|
|
||||||
(insert (haskell-align-imports-chomp
|
|
||||||
(haskell-align-imports-fill padding (car x)))))
|
|
||||||
imports))))
|
|
||||||
nil)
|
|
||||||
|
|
||||||
(defun haskell-align-imports-line-match ()
|
|
||||||
"Try to match the current line as a regexp."
|
|
||||||
(let ((line (buffer-substring-no-properties (line-beginning-position)
|
|
||||||
(line-end-position))))
|
|
||||||
(if (string-match "^import " line)
|
|
||||||
line
|
|
||||||
nil)))
|
|
||||||
|
|
||||||
(defun haskell-align-imports-collect ()
|
|
||||||
"Collect a list of mark / import statement pairs."
|
|
||||||
(let ((imports '()))
|
|
||||||
(while (not (or (equal (point) (point-max)) (haskell-align-imports-after-imports-p)))
|
|
||||||
(let ((line (haskell-align-imports-line-match-it)))
|
|
||||||
(when line
|
|
||||||
(let ((match
|
|
||||||
(haskell-align-imports-merge-parts
|
|
||||||
(cl-loop for i from 1 to 8
|
|
||||||
collect (haskell-align-imports-chomp (match-string i line))))))
|
|
||||||
(setq imports (cons (cons match (line-beginning-position))
|
|
||||||
imports)))))
|
|
||||||
(forward-line))
|
|
||||||
imports))
|
|
||||||
|
|
||||||
(defun haskell-align-imports-merge-parts (l)
|
|
||||||
"Merge together parts of an import statement that shouldn't be separated."
|
|
||||||
(let ((parts (apply #'vector l))
|
|
||||||
(join (lambda (ls)
|
|
||||||
(cl-reduce (lambda (a b)
|
|
||||||
(concat a
|
|
||||||
(if (and (> (length a) 0)
|
|
||||||
(> (length b) 0))
|
|
||||||
" "
|
|
||||||
"")
|
|
||||||
b))
|
|
||||||
ls))))
|
|
||||||
(if haskell-align-imports-pad-after-name
|
|
||||||
(list (funcall join (list (aref parts 0)
|
|
||||||
(aref parts 1)
|
|
||||||
(aref parts 2)))
|
|
||||||
(aref parts 3)
|
|
||||||
(funcall join (list (aref parts 4)
|
|
||||||
(aref parts 5)
|
|
||||||
(aref parts 6)))
|
|
||||||
(aref parts 7))
|
|
||||||
(list (funcall join (list (aref parts 0)
|
|
||||||
(aref parts 1)
|
|
||||||
(aref parts 2)))
|
|
||||||
(funcall join (list (aref parts 3)
|
|
||||||
(aref parts 4)
|
|
||||||
(aref parts 5)
|
|
||||||
(aref parts 6)
|
|
||||||
(aref parts 7)))))))
|
|
||||||
|
|
||||||
(defun haskell-align-imports-chomp (str)
|
|
||||||
"Chomp leading and tailing whitespace from STR."
|
|
||||||
(if str
|
|
||||||
(replace-regexp-in-string "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" ""
|
|
||||||
str)
|
|
||||||
""))
|
|
||||||
|
|
||||||
(defun haskell-align-imports-padding (imports)
|
|
||||||
"Find the padding for each part of the import statements."
|
|
||||||
(if (null imports)
|
|
||||||
imports
|
|
||||||
(cl-reduce (lambda (a b) (cl-mapcar #'max a b))
|
|
||||||
(mapcar (lambda (x) (mapcar #'length (car x)))
|
|
||||||
imports))))
|
|
||||||
|
|
||||||
(defun haskell-align-imports-fill (padding line)
|
|
||||||
"Fill an import line using the padding worked out from all statements."
|
|
||||||
(mapconcat #'identity
|
|
||||||
(cl-mapcar (lambda (pad part)
|
|
||||||
(if (> (length part) 0)
|
|
||||||
(concat part (make-string (- pad (length part)) ? ))
|
|
||||||
(make-string pad ? )))
|
|
||||||
padding
|
|
||||||
line)
|
|
||||||
" "))
|
|
||||||
|
|
||||||
(defun haskell-align-imports-line-match-it ()
|
|
||||||
"Try to match the current line as a regexp."
|
|
||||||
(let ((line (buffer-substring-no-properties (line-beginning-position)
|
|
||||||
(line-end-position))))
|
|
||||||
(if (string-match haskell-align-imports-regexp line)
|
|
||||||
line
|
|
||||||
nil)))
|
|
||||||
|
|
||||||
(defun haskell-align-imports-after-imports-p ()
|
|
||||||
"Are we after the imports list?"
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (line-beginning-position))
|
|
||||||
(not (not (search-forward-regexp "\\( = \\|\\<instance\\>\\| :: \\| ∷ \\)"
|
|
||||||
(line-end-position) t 1)))))
|
|
||||||
|
|
||||||
(provide 'haskell-align-imports)
|
|
||||||
|
|
||||||
;;; haskell-align-imports.el ends here
|
|
Binary file not shown.
@@ -1,178 +0,0 @@
|
|||||||
;;; haskell-bot.el --- A Lambdabot interaction mode
|
|
||||||
|
|
||||||
;; Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
|
||||||
;; Copyright (C) 2001 Chris Webb
|
|
||||||
;; Copyright (C) 1998, 1999 Guy Lapalme
|
|
||||||
|
|
||||||
;; Keywords: inferior mode, Bot interaction mode, Haskell
|
|
||||||
|
|
||||||
;;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 GNU Emacs; see the file COPYING. If not, write to the
|
|
||||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
;; Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Purpose:
|
|
||||||
;;
|
|
||||||
;; To send a Haskell buffer to another buffer running a Bot
|
|
||||||
;; interpreter.
|
|
||||||
;;
|
|
||||||
;; This mode is derived from version 1.1 of Guy Lapalme's
|
|
||||||
;; haskell-hugs.el, which can be obtained from:
|
|
||||||
;;
|
|
||||||
;; http://www.iro.umontreal.ca/~lapalme/Hugs-interaction.html
|
|
||||||
;;
|
|
||||||
;; This in turn was adapted from Chris Van Humbeeck's hugs-mode.el,
|
|
||||||
;; which can be obtained from:
|
|
||||||
;;
|
|
||||||
;; http://www-i2.informatik.rwth-aachen.de/Forschung/FP/Haskell/hugs-mode.el
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; Installation:
|
|
||||||
;;
|
|
||||||
;; To use with Moss and Thorn's haskell-mode.el
|
|
||||||
;;
|
|
||||||
;; http://www.haskell.org/haskell-mode
|
|
||||||
;;
|
|
||||||
;; add this to .emacs:
|
|
||||||
;;
|
|
||||||
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-bot)
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; Customisation:
|
|
||||||
;;
|
|
||||||
;; The name of the Bot interpreter is in haskell-bot-program-name.
|
|
||||||
;;
|
|
||||||
;; Arguments can be sent to the Bot interpreter when it is started by
|
|
||||||
;; setting haskell-bot-program-args (empty by default) to a list of
|
|
||||||
;; string args to pass it. This value can be set interactively by
|
|
||||||
;; calling C-c C-s with an argument (i.e. C-u C-c C-s).
|
|
||||||
;;
|
|
||||||
;; `haskell-bot-hook' is invoked in the *bot* buffer once Bot is
|
|
||||||
;; started.
|
|
||||||
;;
|
|
||||||
;; All functions/variables start with `turn-{on,off}-haskell-bot' or
|
|
||||||
;; `haskell-bot-'.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'comint)
|
|
||||||
|
|
||||||
(defgroup haskell-bot nil
|
|
||||||
"Major mode for interacting with an inferior Bot session."
|
|
||||||
:group 'haskell
|
|
||||||
:prefix "haskell-bot-")
|
|
||||||
|
|
||||||
(define-derived-mode haskell-bot-mode comint-mode "Lambdabot")
|
|
||||||
|
|
||||||
;; Bot interface:
|
|
||||||
|
|
||||||
(require 'comint)
|
|
||||||
(require 'shell)
|
|
||||||
|
|
||||||
(defvar haskell-bot-process nil
|
|
||||||
"The active Bot subprocess corresponding to current buffer.")
|
|
||||||
|
|
||||||
(defvar haskell-bot-process-buffer nil
|
|
||||||
"*Buffer used for communication with Bot subprocess for current buffer.")
|
|
||||||
|
|
||||||
(defcustom haskell-bot-program-name "lambdabot"
|
|
||||||
"*The name of the Bot interpreter program."
|
|
||||||
:type 'string
|
|
||||||
:group 'haskell-bot)
|
|
||||||
|
|
||||||
(defcustom haskell-bot-program-args nil
|
|
||||||
"*A list of string args to pass when starting the Bot interpreter."
|
|
||||||
:type '(repeat string)
|
|
||||||
:group 'haskell-bot)
|
|
||||||
|
|
||||||
(defvar haskell-bot-load-end nil
|
|
||||||
"Position of the end of the last load command.")
|
|
||||||
|
|
||||||
(defvar haskell-bot-error-pos nil
|
|
||||||
"Position of the end of the last load command.")
|
|
||||||
|
|
||||||
(defvar haskell-bot-send-end nil
|
|
||||||
"Position of the end of the last send command.")
|
|
||||||
|
|
||||||
(defvar haskell-bot-comint-prompt-regexp
|
|
||||||
"^lambdabot> "
|
|
||||||
"A regexp that matches the Bot prompt.")
|
|
||||||
|
|
||||||
(defun haskell-bot-start-process (arg)
|
|
||||||
"Start a Bot process and invoke `haskell-bot-hook' if not nil.
|
|
||||||
Prompt for a list of args if called with an argument."
|
|
||||||
(interactive "P")
|
|
||||||
(if arg
|
|
||||||
;; XXX [CDW] Fix to use more natural 'string' version of the
|
|
||||||
;; XXX arguments rather than a sexp.
|
|
||||||
(setq haskell-bot-program-args
|
|
||||||
(read-minibuffer (format "List of args for %s:"
|
|
||||||
haskell-bot-program-name)
|
|
||||||
(prin1-to-string haskell-bot-program-args))))
|
|
||||||
|
|
||||||
;; Start the Bot process in a new comint buffer.
|
|
||||||
(message "Starting Lambdabot process `%s'." haskell-bot-program-name)
|
|
||||||
(setq haskell-bot-process-buffer
|
|
||||||
(apply 'make-comint
|
|
||||||
"lambdabot" haskell-bot-program-name nil
|
|
||||||
haskell-bot-program-args))
|
|
||||||
(setq haskell-bot-process
|
|
||||||
(get-buffer-process haskell-bot-process-buffer))
|
|
||||||
|
|
||||||
;; Select Bot buffer temporarily.
|
|
||||||
(set-buffer haskell-bot-process-buffer)
|
|
||||||
(haskell-bot-mode)
|
|
||||||
(setq comint-prompt-regexp haskell-bot-comint-prompt-regexp)
|
|
||||||
|
|
||||||
;; History syntax of comint conflicts with Haskell, e.g. !!, so better
|
|
||||||
;; turn it off.
|
|
||||||
(setq comint-input-autoexpand nil)
|
|
||||||
(setq comint-process-echoes nil)
|
|
||||||
(run-hooks 'haskell-bot-hook)
|
|
||||||
|
|
||||||
;; Clear message area.
|
|
||||||
(message ""))
|
|
||||||
|
|
||||||
(defun haskell-bot-wait-for-output ()
|
|
||||||
"Wait until output arrives and go to the last input."
|
|
||||||
(while (progn
|
|
||||||
(goto-char comint-last-input-end)
|
|
||||||
(not (re-search-forward comint-prompt-regexp nil t)))
|
|
||||||
(accept-process-output haskell-bot-process)))
|
|
||||||
|
|
||||||
(defun haskell-bot-send (&rest string)
|
|
||||||
"Send `haskell-bot-process' the arguments (one or more strings).
|
|
||||||
A newline is sent after the strings and they are inserted into the
|
|
||||||
current buffer after the last output."
|
|
||||||
(haskell-bot-wait-for-output) ; wait for prompt
|
|
||||||
(goto-char (point-max)) ; position for this input
|
|
||||||
(apply 'insert string)
|
|
||||||
(comint-send-input)
|
|
||||||
(setq haskell-bot-send-end (marker-position comint-last-input-end)))
|
|
||||||
|
|
||||||
(defun haskell-bot-show-bot-buffer ()
|
|
||||||
"Go to the *bot* buffer."
|
|
||||||
(interactive)
|
|
||||||
(if (or (not haskell-bot-process-buffer)
|
|
||||||
(not (buffer-live-p haskell-bot-process-buffer)))
|
|
||||||
(haskell-bot-start-process nil))
|
|
||||||
(pop-to-buffer haskell-bot-process-buffer))
|
|
||||||
|
|
||||||
(provide 'haskell-bot)
|
|
||||||
|
|
||||||
;;; haskell-bot.el ends here
|
|
Binary file not shown.
@@ -1,49 +0,0 @@
|
|||||||
;;; haskell-c.el --- Major mode for *.hsc files
|
|
||||||
|
|
||||||
;; Copyright (C) 2007 Stefan Monnier
|
|
||||||
|
|
||||||
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 GNU Emacs; see the file COPYING. If not, write to
|
|
||||||
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
||||||
;; Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;;
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'haskell-mode)
|
|
||||||
(require 'haskell-font-lock)
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.hsc\\'" . haskell-c-mode))
|
|
||||||
|
|
||||||
(defvar haskell-c-font-lock-keywords
|
|
||||||
`(("^#[ \t]*[[:alnum:]]+" (0 font-lock-preprocessor-face))
|
|
||||||
,@haskell-font-lock-symbols))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-derived-mode haskell-c-mode haskell-mode "Haskell-C"
|
|
||||||
"Major mode for Haskell FFI files."
|
|
||||||
(set (make-local-variable 'font-lock-keywords)
|
|
||||||
(cons 'haskell-c-font-lock-keywords
|
|
||||||
(cdr font-lock-keywords))))
|
|
||||||
|
|
||||||
(provide 'haskell-c)
|
|
||||||
|
|
||||||
;;; haskell-c.el ends here
|
|
Binary file not shown.
@@ -1,951 +0,0 @@
|
|||||||
;;; haskell-cabal.el --- Support for Cabal packages
|
|
||||||
|
|
||||||
;; Copyright (C) 2007, 2008 Stefan Monnier
|
|
||||||
|
|
||||||
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 GNU Emacs; see the file COPYING. If not, write to
|
|
||||||
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
||||||
;; Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Todo:
|
|
||||||
|
|
||||||
;; - distinguish continued lines from indented lines.
|
|
||||||
;; - indent-line-function.
|
|
||||||
;; - outline-minor-mode.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
;; (defun haskell-cabal-extract-fields-from-doc ()
|
|
||||||
;; (require 'xml)
|
|
||||||
;; (with-no-warnings (require 'cl))
|
|
||||||
;; (let ((section (completing-read
|
|
||||||
;; "Section: "
|
|
||||||
;; '("general-fields" "library" "executable" "buildinfo"))))
|
|
||||||
;; (goto-char (point-min))
|
|
||||||
;; (search-forward (concat "<sect3 id=\"" section "\">")))
|
|
||||||
;; (let* ((xml (xml-parse-region
|
|
||||||
;; (progn (search-forward "<variablelist>") (match-beginning 0))
|
|
||||||
;; (progn (search-forward "</variablelist>") (point))))
|
|
||||||
;; (varlist (remove-if-not 'consp (cddar xml)))
|
|
||||||
;; (syms (mapcar (lambda (entry) (caddr (assq 'literal (assq 'term entry))))
|
|
||||||
;; varlist))
|
|
||||||
;; (fields (mapcar (lambda (sym) (substring-no-properties sym 0 -1)) syms)))
|
|
||||||
;; fields))
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'haskell-utils)
|
|
||||||
|
|
||||||
(defconst haskell-cabal-general-fields
|
|
||||||
;; Extracted with (haskell-cabal-extract-fields-from-doc "general-fields")
|
|
||||||
'("name" "version" "cabal-version" "license" "license-file" "copyright"
|
|
||||||
"author" "maintainer" "stability" "homepage" "package-url" "synopsis"
|
|
||||||
"description" "category" "tested-with" "build-depends" "data-files"
|
|
||||||
"extra-source-files" "extra-tmp-files"))
|
|
||||||
|
|
||||||
(defconst haskell-cabal-library-fields
|
|
||||||
;; Extracted with (haskell-cabal-extract-fields-from-doc "library")
|
|
||||||
'("exposed-modules"))
|
|
||||||
|
|
||||||
(defconst haskell-cabal-executable-fields
|
|
||||||
;; Extracted with (haskell-cabal-extract-fields-from-doc "executable")
|
|
||||||
'("executable" "main-is"))
|
|
||||||
|
|
||||||
(defconst haskell-cabal-buildinfo-fields
|
|
||||||
;; Extracted with (haskell-cabal-extract-fields-from-doc "buildinfo")
|
|
||||||
'("buildable" "other-modules" "hs-source-dirs" "extensions" "ghc-options"
|
|
||||||
"ghc-prof-options" "hugs-options" "nhc-options" "includes"
|
|
||||||
"install-includes" "include-dirs" "c-sources" "extra-libraries"
|
|
||||||
"extra-lib-dirs" "cc-options" "ld-options" "frameworks"))
|
|
||||||
|
|
||||||
(defvar haskell-cabal-mode-syntax-table
|
|
||||||
(let ((st (make-syntax-table)))
|
|
||||||
;; The comment syntax can't be described simply in syntax-table.
|
|
||||||
;; We could use font-lock-syntactic-keywords, but is it worth it?
|
|
||||||
;; (modify-syntax-entry ?- ". 12" st)
|
|
||||||
(modify-syntax-entry ?\n ">" st)
|
|
||||||
(modify-syntax-entry ?. "w" st)
|
|
||||||
(modify-syntax-entry ?- "w" st)
|
|
||||||
st))
|
|
||||||
|
|
||||||
(defvar haskell-cabal-font-lock-keywords
|
|
||||||
;; The comment syntax can't be described simply in syntax-table.
|
|
||||||
;; We could use font-lock-syntactic-keywords, but is it worth it?
|
|
||||||
'(("^[ \t]*--.*" . font-lock-comment-face)
|
|
||||||
("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face))
|
|
||||||
("^\\(Library\\)[ \t]*\\({\\|$\\)" (1 font-lock-keyword-face))
|
|
||||||
("^\\(Executable\\|Test-Suite\\|Benchmark\\)[ \t]+\\([^\n \t]*\\)"
|
|
||||||
(1 font-lock-keyword-face) (2 font-lock-function-name-face))
|
|
||||||
("^\\(Flag\\)[ \t]+\\([^\n \t]*\\)"
|
|
||||||
(1 font-lock-keyword-face) (2 font-lock-constant-face))
|
|
||||||
("^\\(Source-Repository\\)[ \t]+\\(head\\|this\\)"
|
|
||||||
(1 font-lock-keyword-face) (2 font-lock-constant-face))
|
|
||||||
("^ *\\(if\\)[ \t]+.*\\({\\|$\\)" (1 font-lock-keyword-face))
|
|
||||||
("^ *\\(}[ \t]*\\)?\\(else\\)[ \t]*\\({\\|$\\)"
|
|
||||||
(2 font-lock-keyword-face))))
|
|
||||||
|
|
||||||
(defvar haskell-cabal-buffers nil
|
|
||||||
"List of Cabal buffers.")
|
|
||||||
|
|
||||||
(defun haskell-cabal-buffers-clean (&optional buffer)
|
|
||||||
(let ((bufs ()))
|
|
||||||
(dolist (buf haskell-cabal-buffers)
|
|
||||||
(if (and (buffer-live-p buf) (not (eq buf buffer))
|
|
||||||
(with-current-buffer buf (derived-mode-p 'haskell-cabal-mode)))
|
|
||||||
(push buf bufs)))
|
|
||||||
(setq haskell-cabal-buffers bufs)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-unregister-buffer ()
|
|
||||||
(haskell-cabal-buffers-clean (current-buffer)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode))
|
|
||||||
|
|
||||||
(defvar haskell-cabal-mode-map
|
|
||||||
(let ((map (make-sparse-keymap)))
|
|
||||||
(define-key map (kbd "C-c C-s") 'haskell-cabal-subsection-arrange-lines)
|
|
||||||
(define-key map (kbd "C-M-n") 'haskell-cabal-next-section)
|
|
||||||
(define-key map (kbd "C-M-p") 'haskell-cabal-previous-section)
|
|
||||||
(define-key map (kbd "M-n") 'haskell-cabal-next-subsection)
|
|
||||||
(define-key map (kbd "M-p") 'haskell-cabal-previous-subsection)
|
|
||||||
(define-key map (kbd "C-<down>") 'haskell-cabal-next-subsection)
|
|
||||||
(define-key map (kbd "C-<up>") 'haskell-cabal-previous-subsection)
|
|
||||||
(define-key map (kbd "C-c C-f") 'haskell-cabal-find-or-create-source-file)
|
|
||||||
(define-key map (kbd "M-g l") 'haskell-cabal-goto-library-section)
|
|
||||||
(define-key map (kbd "M-g e") 'haskell-cabal-goto-executable-section)
|
|
||||||
(define-key map (kbd "M-g b") 'haskell-cabal-goto-benchmark-section)
|
|
||||||
(define-key map (kbd "M-g t") 'haskell-cabal-goto-test-suite-section)
|
|
||||||
map))
|
|
||||||
(defvar haskell-cabal-mode-map (make-sparse-keymap))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-derived-mode haskell-cabal-mode fundamental-mode "Haskell-Cabal"
|
|
||||||
"Major mode for Cabal package description files."
|
|
||||||
(set (make-local-variable 'font-lock-defaults)
|
|
||||||
'(haskell-cabal-font-lock-keywords t t nil nil))
|
|
||||||
(add-to-list 'haskell-cabal-buffers (current-buffer))
|
|
||||||
(add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local)
|
|
||||||
(add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local)
|
|
||||||
(set (make-local-variable 'comment-start) "-- ")
|
|
||||||
(set (make-local-variable 'comment-start-skip) "\\(^[ \t]*\\)--[ \t]*")
|
|
||||||
(set (make-local-variable 'comment-end) "")
|
|
||||||
(set (make-local-variable 'comment-end-skip) "[ \t]*\\(\\s>\\|\n\\)")
|
|
||||||
(set (make-local-variable 'indent-line-function) 'haskell-cabal-indent-line)
|
|
||||||
(setq indent-tabs-mode nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
(defun haskell-cabal-get-setting (name)
|
|
||||||
(save-excursion
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(when (re-search-forward
|
|
||||||
(concat "^[ \t]*" (regexp-quote name)
|
|
||||||
":[ \t]*\\(.*\\(\n[ \t]+[ \t\n].*\\)*\\)")
|
|
||||||
nil t)
|
|
||||||
(let ((val (match-string 1))
|
|
||||||
(start 1))
|
|
||||||
(when (match-end 2) ;Multiple lines.
|
|
||||||
;; The documentation is not very precise about what to do about
|
|
||||||
;; the \n and the indentation: are they part of the value or
|
|
||||||
;; the encoding? I take the point of view that \n is part of
|
|
||||||
;; the value (so that values can span multiple lines as well),
|
|
||||||
;; and that only the first char in the indentation is part of
|
|
||||||
;; the encoding, the rest is part of the value (otherwise, lines
|
|
||||||
;; in the value cannot start with spaces or tabs).
|
|
||||||
(while (string-match "^[ \t]\\(?:\\.$\\)?" val start)
|
|
||||||
(setq start (1+ (match-beginning 0)))
|
|
||||||
(setq val (replace-match "" t t val))))
|
|
||||||
val)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-guess-setting (name)
|
|
||||||
"Guess the specified setting of this project.
|
|
||||||
If there is no valid .cabal file to get the setting from (or
|
|
||||||
there is no corresponding setting with that name in the .cabal
|
|
||||||
file), then this function returns nil."
|
|
||||||
(interactive)
|
|
||||||
(when (and name buffer-file-name)
|
|
||||||
(let ((cabal-file (haskell-cabal-find-file (file-name-directory buffer-file-name))))
|
|
||||||
(when (and cabal-file (file-readable-p cabal-file))
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents cabal-file)
|
|
||||||
(haskell-cabal-get-setting name))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-cabal-get-dir ()
|
|
||||||
"Get the Cabal dir for a new project. Various ways of figuring this out,
|
|
||||||
and indeed just prompting the user. Do them all."
|
|
||||||
(let* ((file (haskell-cabal-find-file))
|
|
||||||
(dir (when file (file-name-directory file))))
|
|
||||||
(haskell-utils-read-directory-name
|
|
||||||
(format "Cabal dir%s: " (if file (format " (guessed from %s)" (file-relative-name file)) ""))
|
|
||||||
dir)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-compute-checksum (dir)
|
|
||||||
"Compute MD5 checksum of package description file in DIR.
|
|
||||||
Return nil if no Cabal description file could be located via
|
|
||||||
`haskell-cabal-find-pkg-desc'."
|
|
||||||
(let ((cabal-file (haskell-cabal-find-pkg-desc dir)))
|
|
||||||
(when cabal-file
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents cabal-file)
|
|
||||||
(md5 (buffer-string))))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-find-file (&optional dir)
|
|
||||||
"Search for package description file upwards starting from DIR.
|
|
||||||
If DIR is nil, `default-directory' is used as starting point for
|
|
||||||
directory traversal. Upward traversal is aborted if file owner
|
|
||||||
changes. Uses`haskell-cabal-find-pkg-desc' internally."
|
|
||||||
(catch 'found
|
|
||||||
(let ((user (nth 2 (file-attributes (or dir default-directory))))
|
|
||||||
;; Abbreviate, so as to stop when we cross ~/.
|
|
||||||
(root (abbreviate-file-name (or dir default-directory))))
|
|
||||||
;; traverse current dir up to root as long as file owner doesn't change
|
|
||||||
(while (and root (equal user (nth 2 (file-attributes root))))
|
|
||||||
(let ((cabal-file (haskell-cabal-find-pkg-desc root)))
|
|
||||||
(when cabal-file
|
|
||||||
(throw 'found cabal-file)))
|
|
||||||
|
|
||||||
(let ((proot (file-name-directory (directory-file-name root))))
|
|
||||||
(if (equal proot root) ;; fix-point reached?
|
|
||||||
(throw 'found nil)
|
|
||||||
(setq root proot))))
|
|
||||||
nil)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-find-pkg-desc (dir &optional allow-multiple)
|
|
||||||
"Find a package description file in the directory DIR.
|
|
||||||
Returns nil if none or multiple \".cabal\" files were found. If
|
|
||||||
ALLOW-MULTIPLE is non nil, in case of multiple \".cabal\" files,
|
|
||||||
a list is returned instead of failing with a nil result."
|
|
||||||
;; This is basically a port of Cabal's
|
|
||||||
;; Distribution.Simple.Utils.findPackageDesc function
|
|
||||||
;; http://hackage.haskell.org/packages/archive/Cabal/1.16.0.3/doc/html/Distribution-Simple-Utils.html
|
|
||||||
;; but without the exception throwing.
|
|
||||||
(let* ((cabal-files
|
|
||||||
(cl-remove-if 'file-directory-p
|
|
||||||
(cl-remove-if-not 'file-exists-p
|
|
||||||
(directory-files dir t ".\\.cabal\\'")))))
|
|
||||||
(cond
|
|
||||||
((= (length cabal-files) 1) (car cabal-files)) ;; exactly one candidate found
|
|
||||||
(allow-multiple cabal-files) ;; pass-thru multiple candidates
|
|
||||||
(t nil))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-find-dir (&optional dir)
|
|
||||||
"Like `haskell-cabal-find-file' but returns directory instead.
|
|
||||||
See `haskell-cabal-find-file' for meaning of DIR argument."
|
|
||||||
(let ((cabal-file (haskell-cabal-find-file dir)))
|
|
||||||
(when cabal-file
|
|
||||||
(file-name-directory cabal-file))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-cabal-visit-file (other-window)
|
|
||||||
"Locate and visit package description file for file visited by current buffer.
|
|
||||||
This uses `haskell-cabal-find-file' to locate the closest
|
|
||||||
\".cabal\" file and open it. This command assumes a common Cabal
|
|
||||||
project structure where the \".cabal\" file is in the top-folder
|
|
||||||
of the project, and all files related to the project are in or
|
|
||||||
below the top-folder. If called with non-nil prefix argument
|
|
||||||
OTHER-WINDOW use `find-file-other-window'."
|
|
||||||
(interactive "P")
|
|
||||||
;; Note: We aren't allowed to rely on haskell-session here (which,
|
|
||||||
;; in pathological cases, can have a different .cabal file
|
|
||||||
;; associated with the current buffer)
|
|
||||||
(if buffer-file-name
|
|
||||||
(let ((cabal-file (haskell-cabal-find-file (file-name-directory buffer-file-name))))
|
|
||||||
(if cabal-file
|
|
||||||
(if other-window
|
|
||||||
(find-file-other-window cabal-file)
|
|
||||||
(find-file cabal-file))
|
|
||||||
(error "Could not locate \".cabal\" file for %S" buffer-file-name)))
|
|
||||||
(error "Cannot locate \".cabal\" file for buffers not visiting any file")))
|
|
||||||
|
|
||||||
(defvar haskell-cabal-commands
|
|
||||||
'("install"
|
|
||||||
"update"
|
|
||||||
"list"
|
|
||||||
"info"
|
|
||||||
"upgrade"
|
|
||||||
"fetch"
|
|
||||||
"unpack"
|
|
||||||
"check"
|
|
||||||
"sdist"
|
|
||||||
"upload"
|
|
||||||
"report"
|
|
||||||
"init"
|
|
||||||
"configure"
|
|
||||||
"build"
|
|
||||||
"copy"
|
|
||||||
"haddock"
|
|
||||||
"clean"
|
|
||||||
"hscolour"
|
|
||||||
"register"
|
|
||||||
"test"
|
|
||||||
"help"))
|
|
||||||
|
|
||||||
|
|
||||||
(defgroup haskell-cabal nil
|
|
||||||
"Haskell cabal files"
|
|
||||||
:group 'haskell
|
|
||||||
)
|
|
||||||
|
|
||||||
(defcustom haskell-cabal-list-comma-position
|
|
||||||
'before
|
|
||||||
"Where to put the comma in lists"
|
|
||||||
:safe t
|
|
||||||
:group 'haskell-cabal
|
|
||||||
:type '(choice (const before)
|
|
||||||
(const after)))
|
|
||||||
|
|
||||||
(defconst haskell-cabal-section-header-regexp "^[[:alnum:]]" )
|
|
||||||
(defconst haskell-cabal-subsection-header-regexp "^[ \t]*[[:alnum:]]\\w*:")
|
|
||||||
(defconst haskell-cabal-comment-regexp "^[ \t]*--")
|
|
||||||
(defconst haskell-cabal-empty-regexp "^[ \t]*$")
|
|
||||||
(defconst haskell-cabal-conditional-regexp "^[ \t]*\\(\\if\\|else\\|}\\)")
|
|
||||||
|
|
||||||
(defun haskell-cabal-classify-line ()
|
|
||||||
"Classify the current line into 'section-header 'subsection-header 'section-data 'comment and 'empty '"
|
|
||||||
(save-excursion
|
|
||||||
(beginning-of-line)
|
|
||||||
(cond
|
|
||||||
((looking-at haskell-cabal-subsection-header-regexp ) 'subsection-header)
|
|
||||||
((looking-at haskell-cabal-section-header-regexp) 'section-header)
|
|
||||||
((looking-at haskell-cabal-comment-regexp) 'comment)
|
|
||||||
((looking-at haskell-cabal-empty-regexp ) 'empty)
|
|
||||||
((looking-at haskell-cabal-conditional-regexp ) 'conditional)
|
|
||||||
(t 'section-data))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-header-p ()
|
|
||||||
"Is the current line a section or subsection header?"
|
|
||||||
(cl-case (haskell-cabal-classify-line)
|
|
||||||
((section-header subsection-header) t)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-header-p ()
|
|
||||||
"Is the current line a section or subsection header?"
|
|
||||||
(cl-case (haskell-cabal-classify-line)
|
|
||||||
((section-header) t)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-beginning ()
|
|
||||||
"Find the beginning of the current section"
|
|
||||||
(save-excursion
|
|
||||||
(while (not (or (bobp) (haskell-cabal-section-header-p)))
|
|
||||||
(forward-line -1))
|
|
||||||
(point)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-beginning-of-section ()
|
|
||||||
"go to the beginning of the section"
|
|
||||||
(interactive)
|
|
||||||
(goto-char (haskell-cabal-section-beginning))
|
|
||||||
)
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-end ()
|
|
||||||
"Find the end of the current section"
|
|
||||||
(interactive)
|
|
||||||
(save-excursion
|
|
||||||
(if (re-search-forward "\n\\([ \t]*\n\\)*[[:alnum:]]" nil t)
|
|
||||||
(match-beginning 0)
|
|
||||||
(point-max))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-end-of-section ()
|
|
||||||
"go to the end of the section"
|
|
||||||
(interactive)
|
|
||||||
(goto-char (haskell-cabal-section-end)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-next-section ()
|
|
||||||
"Go to the next extion"
|
|
||||||
(interactive)
|
|
||||||
(when (haskell-cabal-section-header-p) (forward-line))
|
|
||||||
(while (not (or (eobp) (haskell-cabal-section-header-p)))
|
|
||||||
(forward-line)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-previous-section ()
|
|
||||||
"Go to the next extion"
|
|
||||||
(interactive)
|
|
||||||
(when (haskell-cabal-section-header-p) (forward-line -1))
|
|
||||||
(while (not (or (bobp) (haskell-cabal-section-header-p)))
|
|
||||||
(forward-line -1)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-subsection-end ()
|
|
||||||
"find the end of the current subsection"
|
|
||||||
(save-excursion
|
|
||||||
(haskell-cabal-beginning-of-subsection)
|
|
||||||
(forward-line)
|
|
||||||
(while (and (not (eobp))
|
|
||||||
(member (haskell-cabal-classify-line) '(empty section-data)))
|
|
||||||
(forward-line))
|
|
||||||
(unless (eobp) (forward-line -1))
|
|
||||||
(while (and (equal (haskell-cabal-classify-line) 'empty)
|
|
||||||
(not (bobp)))
|
|
||||||
(forward-line -1))
|
|
||||||
(end-of-line)
|
|
||||||
(point)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-end-of-subsection ()
|
|
||||||
"go to the end of the current subsection"
|
|
||||||
(interactive)
|
|
||||||
(goto-char (haskell-cabal-subsection-end)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-section ()
|
|
||||||
"Get the name and data of the associated section"
|
|
||||||
(save-excursion
|
|
||||||
(haskell-cabal-beginning-of-section)
|
|
||||||
(when (and (haskell-cabal-section-header-p)
|
|
||||||
(looking-at "^\\(\\w+\\)[ \t]*\\(.*\\)$"))
|
|
||||||
(list :name (match-string-no-properties 1)
|
|
||||||
:value (match-string-no-properties 2)
|
|
||||||
:beginning (match-beginning 0)
|
|
||||||
:end (haskell-cabal-section-end)))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-subsection ()
|
|
||||||
"Get the name and bounds of of the current subsection"
|
|
||||||
(save-excursion
|
|
||||||
(haskell-cabal-beginning-of-subsection)
|
|
||||||
(when (looking-at "\\([ \t]*\\(\\w*\\):\\)[ \t]*")
|
|
||||||
(list :name (match-string-no-properties 2)
|
|
||||||
:beginning (match-end 0)
|
|
||||||
:end (save-match-data (haskell-cabal-subsection-end))
|
|
||||||
:data-start-column (save-excursion (goto-char (match-end 0))
|
|
||||||
(current-column)
|
|
||||||
)))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-name (section)
|
|
||||||
(plist-get section :name))
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-value (section)
|
|
||||||
(plist-get section :value))
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-start (section)
|
|
||||||
(plist-get section :beginning))
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-data-start-column (section)
|
|
||||||
(plist-get section :data-start-column))
|
|
||||||
|
|
||||||
(defmacro haskell-cabal-with-subsection (subsection replace &rest funs)
|
|
||||||
"Copy subsection data into a temporary buffer, save indentation
|
|
||||||
and execute FORMS
|
|
||||||
|
|
||||||
If REPLACE is non-nil the subsection data is replaced with the
|
|
||||||
resultung buffer-content"
|
|
||||||
(let ((section (make-symbol "section"))
|
|
||||||
(beg (make-symbol "beg"))
|
|
||||||
(end (make-symbol "end"))
|
|
||||||
(start-col (make-symbol "start-col"))
|
|
||||||
(section-data (make-symbol "section-data")))
|
|
||||||
`(let* ((,section ,subsection)
|
|
||||||
(,beg (plist-get ,section :beginning))
|
|
||||||
(,end (plist-get ,section :end))
|
|
||||||
(,start-col (plist-get ,section :data-start-column))
|
|
||||||
(,section-data (buffer-substring ,beg ,end))
|
|
||||||
(section-name (plist-get ,section :name )))
|
|
||||||
(save-excursion
|
|
||||||
(prog1
|
|
||||||
(with-temp-buffer
|
|
||||||
(setq indent-tabs-mode nil)
|
|
||||||
(indent-to ,start-col)
|
|
||||||
(insert ,section-data)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(prog1
|
|
||||||
(progn (haskell-cabal-save-indentation ,@funs))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(when (looking-at (format "[ ]\\{0,%d\\}" (1+ ,start-col)))
|
|
||||||
(replace-match ""))
|
|
||||||
|
|
||||||
(setq ,section-data (buffer-substring (point-min) (point-max)))))
|
|
||||||
,@(when replace
|
|
||||||
`((delete-region ,beg ,end)
|
|
||||||
(goto-char ,beg)
|
|
||||||
(insert ,section-data))))))))
|
|
||||||
|
|
||||||
(defmacro haskell-cabal-each-line (&rest fun)
|
|
||||||
"Execute FOMRS on each line"
|
|
||||||
`(save-excursion
|
|
||||||
(while (< (point) (point-max))
|
|
||||||
,@fun
|
|
||||||
(forward-line))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-chomp-line ()
|
|
||||||
"Remove leading and trailing whitespaces from current line"
|
|
||||||
(beginning-of-line)
|
|
||||||
(when (looking-at "^[ \t]*\\([^ \t]\\|\\(?:[^ \t].*[^ \t]\\)\\)[ \t]*$")
|
|
||||||
(replace-match (match-string 1) nil t)
|
|
||||||
t))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-min-indentation (&optional beg end)
|
|
||||||
"Compute largest common whitespace prefix of each line in between BEG and END"
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (or beg (point-min)))
|
|
||||||
(let ((min-indent nil))
|
|
||||||
(while (< (point) (or end (point-max)))
|
|
||||||
(let ((indent (current-indentation)))
|
|
||||||
(if (and (not (haskell-cabal-ignore-line-p))
|
|
||||||
(or (not min-indent)
|
|
||||||
(< indent min-indent)))
|
|
||||||
(setq min-indent indent)))
|
|
||||||
(forward-line))
|
|
||||||
min-indent)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-ignore-line-p ()
|
|
||||||
"Does line only contain whitespaces and comments?"
|
|
||||||
(save-excursion
|
|
||||||
(beginning-of-line)
|
|
||||||
(looking-at "^[ \t]*\\(?:--.*\\)?$")))
|
|
||||||
|
|
||||||
(defun haskell-cabal-kill-indentation ()
|
|
||||||
"Remove longest common whitespace prefix from each line"
|
|
||||||
(goto-char (point-min))
|
|
||||||
(let ((indent (haskell-cabal-min-indentation)))
|
|
||||||
(haskell-cabal-each-line (unless (haskell-cabal-ignore-line-p)
|
|
||||||
(delete-char indent)) )
|
|
||||||
indent))
|
|
||||||
|
|
||||||
(defun haskell-cabal-add-indentation (indent)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(haskell-cabal-each-line
|
|
||||||
(unless (haskell-cabal-ignore-line-p)
|
|
||||||
(indent-to indent))))
|
|
||||||
|
|
||||||
|
|
||||||
(defmacro haskell-cabal-save-indentation (&rest funs)
|
|
||||||
"Strip indentation from each line, execute FORMS and reinstate indentation
|
|
||||||
so that the indentation of the FIRST LINE matches"
|
|
||||||
(let ((old-l1-indent (make-symbol "new-l1-indent"))
|
|
||||||
(new-l1-indent (make-symbol "old-l1-indent"))
|
|
||||||
(res nil))
|
|
||||||
`(let ( (,old-l1-indent (save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(current-indentation))))
|
|
||||||
(unwind-protect
|
|
||||||
(progn
|
|
||||||
(haskell-cabal-kill-indentation)
|
|
||||||
,@funs)
|
|
||||||
(progn
|
|
||||||
(goto-char (point-min))
|
|
||||||
(let ((,new-l1-indent (current-indentation)))
|
|
||||||
(haskell-cabal-add-indentation (- ,old-l1-indent
|
|
||||||
,new-l1-indent))))))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-strip-list ()
|
|
||||||
"strip commas from comma-seperated list"
|
|
||||||
(goto-char (point-min))
|
|
||||||
;; split list items on single line
|
|
||||||
(while (re-search-forward
|
|
||||||
"\\([^ \t,\n]\\)[ \t]*,[ \t]*\\([^ \t,\n]\\)" nil t)
|
|
||||||
(replace-match "\\1\n\\2" nil nil))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t)
|
|
||||||
(replace-match "" nil nil))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (re-search-forward ",[ \t]*$" nil t)
|
|
||||||
(replace-match "" nil nil))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(haskell-cabal-each-line (haskell-cabal-chomp-line)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-listify ()
|
|
||||||
"Add commas so that buffer contains a comma-seperated list"
|
|
||||||
(cl-case haskell-cabal-list-comma-position
|
|
||||||
('before
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (haskell-cabal-ignore-line-p) (forward-line))
|
|
||||||
(indent-to 2)
|
|
||||||
(forward-line)
|
|
||||||
(haskell-cabal-each-line
|
|
||||||
(unless (haskell-cabal-ignore-line-p)
|
|
||||||
(insert ", "))))
|
|
||||||
('after
|
|
||||||
(goto-char (point-max))
|
|
||||||
(while (not (bobp))
|
|
||||||
(unless (haskell-cabal-ignore-line-p)
|
|
||||||
(forward-line -1)
|
|
||||||
(end-of-line)
|
|
||||||
(insert ",")
|
|
||||||
(beginning-of-line))))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defmacro haskell-cabal-with-cs-list (&rest funs)
|
|
||||||
"format buffer so that each line contains a list element "
|
|
||||||
`(progn
|
|
||||||
(save-excursion (haskell-cabal-strip-list))
|
|
||||||
(unwind-protect (progn ,@funs)
|
|
||||||
(haskell-cabal-listify))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-sort-lines-key-fun ()
|
|
||||||
(when (looking-at "[ \t]*--[ \t,]*")
|
|
||||||
(goto-char (match-end 0)))
|
|
||||||
nil)
|
|
||||||
|
|
||||||
(defmacro haskell-cabal-save-position (&rest forms)
|
|
||||||
"Save position as mark, execute FORMs and go back to mark"
|
|
||||||
`(prog2
|
|
||||||
(haskell-cabal-mark)
|
|
||||||
(progn ,@forms)
|
|
||||||
(haskell-cabal-goto-mark)
|
|
||||||
(haskell-cabal-remove-mark)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-subsection-arrange-lines ()
|
|
||||||
"Sort lines of current subsection"
|
|
||||||
(interactive)
|
|
||||||
(haskell-cabal-save-position
|
|
||||||
(haskell-cabal-with-subsection
|
|
||||||
(haskell-cabal-subsection) t
|
|
||||||
(haskell-cabal-with-cs-list
|
|
||||||
(sort-subr nil 'forward-line 'end-of-line
|
|
||||||
'haskell-cabal-sort-lines-key-fun)
|
|
||||||
))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-subsection-beginning ()
|
|
||||||
"find the beginning of the current subsection"
|
|
||||||
(save-excursion
|
|
||||||
(while (and (not (bobp))
|
|
||||||
(not (haskell-cabal-header-p)))
|
|
||||||
(forward-line -1))
|
|
||||||
(back-to-indentation)
|
|
||||||
(point)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-beginning-of-subsection ()
|
|
||||||
"go to the beginniing of the current subsection"
|
|
||||||
(interactive)
|
|
||||||
(goto-char (haskell-cabal-subsection-beginning)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-next-subsection ()
|
|
||||||
"go to the next subsection"
|
|
||||||
(interactive)
|
|
||||||
(if (haskell-cabal-header-p) (forward-line))
|
|
||||||
(while (and (not (eobp))
|
|
||||||
(not (haskell-cabal-header-p)))
|
|
||||||
(forward-line))
|
|
||||||
(haskell-cabal-forward-to-line-entry))
|
|
||||||
|
|
||||||
(defun haskell-cabal-previous-subsection ()
|
|
||||||
"go to the next subsection"
|
|
||||||
(interactive)
|
|
||||||
(if (haskell-cabal-header-p) (forward-line -1))
|
|
||||||
(while (and (not (bobp))
|
|
||||||
(not (haskell-cabal-header-p)))
|
|
||||||
(forward-line -1))
|
|
||||||
(haskell-cabal-forward-to-line-entry)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-find-subsection-by (section pred)
|
|
||||||
"Find sunsection with name NAME"
|
|
||||||
(save-excursion
|
|
||||||
(when section (goto-char (haskell-cabal-section-start section)))
|
|
||||||
(let* ((end (if section (haskell-cabal-section-end) (point-max)))
|
|
||||||
(found nil))
|
|
||||||
(while (and (< (point) end)
|
|
||||||
(not found))
|
|
||||||
(let ((subsection (haskell-cabal-subsection)))
|
|
||||||
(when (and subsection (funcall pred subsection))
|
|
||||||
(setq found subsection)))
|
|
||||||
(haskell-cabal-next-subsection))
|
|
||||||
found)))
|
|
||||||
|
|
||||||
(defun haskell-cabal-find-subsection (section name)
|
|
||||||
"Find sunsection with name NAME"
|
|
||||||
(let ((downcase-name (downcase name)))
|
|
||||||
(haskell-cabal-find-subsection-by
|
|
||||||
section
|
|
||||||
'(lambda (subsection)
|
|
||||||
(string= (downcase (haskell-cabal-section-name subsection))
|
|
||||||
downcase-name)))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-subsection (name)
|
|
||||||
(let ((subsection (haskell-cabal-find-subsection (haskell-cabal-section) name)))
|
|
||||||
(when subsection
|
|
||||||
(goto-char (haskell-cabal-section-start subsection)))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-exposed-modules ()
|
|
||||||
(interactive)
|
|
||||||
(haskell-cabal-goto-subsection "exposed-modules"))
|
|
||||||
|
|
||||||
(defun haskell-cabal-subsection-entry-list (section name)
|
|
||||||
"Get the data of a subsection as a list"
|
|
||||||
(let ((subsection (haskell-cabal-find-subsection section name)))
|
|
||||||
(when subsection
|
|
||||||
(haskell-cabal-with-subsection
|
|
||||||
subsection nil
|
|
||||||
(haskell-cabal-with-cs-list
|
|
||||||
(delete-matching-lines
|
|
||||||
(format "\\(?:%s\\)\\|\\(?:%s\\)"
|
|
||||||
haskell-cabal-comment-regexp
|
|
||||||
haskell-cabal-empty-regexp)
|
|
||||||
(point-min) (point-max))
|
|
||||||
(split-string (buffer-substring-no-properties (point-min) (point-max))
|
|
||||||
"\n" t))))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-remove-mark ()
|
|
||||||
(remove-list-of-text-properties (point-min) (point-max)
|
|
||||||
'(haskell-cabal-marker)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-mark ()
|
|
||||||
"Mark the current position with the text property haskell-cabal-marker"
|
|
||||||
(haskell-cabal-remove-mark)
|
|
||||||
(put-text-property (line-beginning-position) (line-end-position)
|
|
||||||
'haskell-cabal-marker 'marked-line)
|
|
||||||
(put-text-property (point) (1+ (point))
|
|
||||||
'haskell-cabal-marker 'marked))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-mark ()
|
|
||||||
"Go to marked line"
|
|
||||||
(let ((marked-pos (text-property-any (point-min) (point-max)
|
|
||||||
'haskell-cabal-marker
|
|
||||||
'marked))
|
|
||||||
(marked-line (text-property-any (point-min) (point-max)
|
|
||||||
'haskell-cabal-marker
|
|
||||||
'marked-line) )
|
|
||||||
)
|
|
||||||
(cond (marked-pos (goto-char marked-pos))
|
|
||||||
(marked-line (goto-char marked-line)))))
|
|
||||||
|
|
||||||
(defmacro haskell-cabal-with-subsection-line (replace &rest forms)
|
|
||||||
"Mark line and "
|
|
||||||
`(progn
|
|
||||||
(haskell-cabal-mark)
|
|
||||||
(unwind-protect
|
|
||||||
(haskell-cabal-with-subsection (haskell-cabal-subsection) ,replace
|
|
||||||
(haskell-cabal-goto-mark)
|
|
||||||
,@forms)
|
|
||||||
(haskell-cabal-remove-mark))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-get-line-content ()
|
|
||||||
(haskell-cabal-with-subsection-line
|
|
||||||
nil
|
|
||||||
(haskell-cabal-with-cs-list
|
|
||||||
(haskell-cabal-goto-mark)
|
|
||||||
(buffer-substring-no-properties (line-beginning-position)
|
|
||||||
(line-end-position)))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-module-to-filename (module)
|
|
||||||
(concat (replace-regexp-in-string "[.]" "/" module ) ".hs"))
|
|
||||||
|
|
||||||
(defconst haskell-cabal-module-sections '("exposed-modules" "other-modules")
|
|
||||||
"List of sections that contain module names"
|
|
||||||
)
|
|
||||||
|
|
||||||
(defconst haskell-cabal-file-sections
|
|
||||||
'("main-is" "c-sources" "data-files" "extra-source-files"
|
|
||||||
"extra-doc-files" "extra-tmp-files" )
|
|
||||||
"List of subsections that contain filenames"
|
|
||||||
)
|
|
||||||
|
|
||||||
(defconst haskell-cabal-source-bearing-sections
|
|
||||||
'("library" "executable" "test-suite" "benchmark"))
|
|
||||||
|
|
||||||
(defun haskell-cabal-source-section-p (section)
|
|
||||||
(not (not (member (downcase (haskell-cabal-section-name section))
|
|
||||||
haskell-cabal-source-bearing-sections))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-line-filename ()
|
|
||||||
"Expand filename in current line according to the subsection type
|
|
||||||
|
|
||||||
Module names in exposed-modules and other-modules are expanded by replacing each dot (.) in the module name with a foward slash (/) and appending \".hs\"
|
|
||||||
|
|
||||||
Example: Foo.Bar.Quux ==> Foo/Bar/Quux.hs
|
|
||||||
|
|
||||||
Source names from main-is and c-sources sections are left untouched
|
|
||||||
|
|
||||||
"
|
|
||||||
(let ((entry (haskell-cabal-get-line-content))
|
|
||||||
(subsection (downcase (haskell-cabal-section-name
|
|
||||||
(haskell-cabal-subsection)))))
|
|
||||||
(cond ((member subsection haskell-cabal-module-sections)
|
|
||||||
(haskell-cabal-module-to-filename entry))
|
|
||||||
((member subsection haskell-cabal-file-sections) entry))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-join-paths (&rest args)
|
|
||||||
"Crude hack to replace f-join"
|
|
||||||
(mapconcat 'identity args "/")
|
|
||||||
)
|
|
||||||
|
|
||||||
(defun haskell-cabal-find-or-create-source-file ()
|
|
||||||
"Open the source file this line refers to"
|
|
||||||
(interactive)
|
|
||||||
(let* ((src-dirs (append (haskell-cabal-subsection-entry-list
|
|
||||||
(haskell-cabal-section) "hs-source-dirs")
|
|
||||||
'("")))
|
|
||||||
(base-dir (file-name-directory (buffer-file-name)))
|
|
||||||
(filename (haskell-cabal-line-filename)))
|
|
||||||
(when filename
|
|
||||||
(let ((candidates
|
|
||||||
(delq nil (mapcar
|
|
||||||
(lambda (dir)
|
|
||||||
(let ((file (haskell-cabal-join-paths base-dir dir filename)))
|
|
||||||
(when (and (file-readable-p file)
|
|
||||||
(not (file-directory-p file)))
|
|
||||||
file)))
|
|
||||||
src-dirs))))
|
|
||||||
(if (null candidates)
|
|
||||||
(let* ((src-dir (haskell-cabal-join-paths base-dir (or (car src-dirs) "")))
|
|
||||||
(newfile (haskell-cabal-join-paths src-dir filename))
|
|
||||||
(subdir (file-name-directory newfile))
|
|
||||||
(do-create-p (y-or-n-p (format "Create file %s ?" newfile))))
|
|
||||||
(when do-create-p
|
|
||||||
(find-file-other-window newfile )))
|
|
||||||
(find-file-other-window (car candidates)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-find-section-type (type &optional wrap)
|
|
||||||
(save-excursion
|
|
||||||
(haskell-cabal-next-section)
|
|
||||||
(while
|
|
||||||
(not
|
|
||||||
(or
|
|
||||||
(eobp)
|
|
||||||
(string=
|
|
||||||
(downcase type)
|
|
||||||
(downcase (haskell-cabal-section-name (haskell-cabal-section))))))
|
|
||||||
(haskell-cabal-next-section))
|
|
||||||
(if (eobp)
|
|
||||||
(if wrap (progn
|
|
||||||
(goto-char (point-min))
|
|
||||||
(haskell-cabal-find-section-type type nil) )
|
|
||||||
nil)
|
|
||||||
(point))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-section-type (type)
|
|
||||||
(let ((section (haskell-cabal-find-section-type type t)))
|
|
||||||
(if section (goto-char section)
|
|
||||||
(message "No %s section found" type))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-library-section ()
|
|
||||||
(interactive)
|
|
||||||
(haskell-cabal-goto-section-type "library"))
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-test-suite-section ()
|
|
||||||
(interactive)
|
|
||||||
(haskell-cabal-goto-section-type "test-suite"))
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-executable-section ()
|
|
||||||
(interactive)
|
|
||||||
(haskell-cabal-goto-section-type "executable"))
|
|
||||||
|
|
||||||
(defun haskell-cabal-goto-benchmark-section ()
|
|
||||||
(interactive)
|
|
||||||
(haskell-cabal-goto-section-type "benchmark"))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-cabal-line-entry-column ()
|
|
||||||
"Column at which the line entry starts"
|
|
||||||
(save-excursion
|
|
||||||
(cl-case (haskell-cabal-classify-line)
|
|
||||||
(section-data (beginning-of-line)
|
|
||||||
(when (looking-at "[ ]*\\(?:,[ ]*\\)?")
|
|
||||||
(goto-char (match-end 0))
|
|
||||||
(current-column)))
|
|
||||||
(subsection-header
|
|
||||||
(haskell-cabal-section-data-start-column (haskell-cabal-subsection))))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-forward-to-line-entry ()
|
|
||||||
"go forward to the beginning of the line entry (but never move backwards)"
|
|
||||||
(let ((col (haskell-cabal-line-entry-column)))
|
|
||||||
(when (and col (< (current-column) col))
|
|
||||||
(beginning-of-line)
|
|
||||||
(forward-char col))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-indent-line ()
|
|
||||||
"Indent current line according to subsection"
|
|
||||||
(interactive)
|
|
||||||
(cl-case (haskell-cabal-classify-line)
|
|
||||||
(section-data
|
|
||||||
(save-excursion
|
|
||||||
(let ((indent (haskell-cabal-section-data-start-column
|
|
||||||
(haskell-cabal-subsection))))
|
|
||||||
(indent-line-to indent)
|
|
||||||
(beginning-of-line)
|
|
||||||
(when (looking-at "[ ]*\\([ ]\\{2\\},[ ]*\\)")
|
|
||||||
(replace-match ", " t t nil 1)))))
|
|
||||||
(empty
|
|
||||||
(indent-relative)))
|
|
||||||
(haskell-cabal-forward-to-line-entry))
|
|
||||||
|
|
||||||
(defun haskell-cabal-map-sections (fun)
|
|
||||||
"Execute fun over each section, collecting the result"
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(let ((results nil))
|
|
||||||
(while (not (eobp))
|
|
||||||
(let* ((section (haskell-cabal-section))
|
|
||||||
(result (and section (funcall fun (haskell-cabal-section)))))
|
|
||||||
(when section (setq results (cons result results))))
|
|
||||||
(haskell-cabal-next-section))
|
|
||||||
(nreverse results))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-section-add-build-dependency (dependency &optional sort sec)
|
|
||||||
"Add a build dependency to the build-depends section"
|
|
||||||
(let* ((section (or sec (haskell-cabal-section)))
|
|
||||||
(subsection (and section
|
|
||||||
(haskell-cabal-find-subsection section "build-depends"))))
|
|
||||||
(when subsection
|
|
||||||
(haskell-cabal-with-subsection
|
|
||||||
subsection t
|
|
||||||
(haskell-cabal-with-cs-list
|
|
||||||
(insert dependency)
|
|
||||||
(insert "\n")
|
|
||||||
(when sort
|
|
||||||
(goto-char (point-min))
|
|
||||||
(sort-subr nil 'forward-line 'end-of-line
|
|
||||||
'haskell-cabal-sort-lines-key-fun)))))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-add-build-dependency (dependency &optional sort silent)
|
|
||||||
"Add a build dependencies to sections"
|
|
||||||
(haskell-cabal-map-sections
|
|
||||||
(lambda (section)
|
|
||||||
(when (haskell-cabal-source-section-p section)
|
|
||||||
(when (or silent
|
|
||||||
(y-or-n-p (format "Add dependency %s to %s section %s?"
|
|
||||||
dependency
|
|
||||||
(haskell-cabal-section-name section)
|
|
||||||
(haskell-cabal-section-value section))))
|
|
||||||
(haskell-cabal-section-add-build-dependency dependency sort section)
|
|
||||||
nil)))))
|
|
||||||
|
|
||||||
(defun haskell-cabal-add-dependency (package &optional version no-prompt
|
|
||||||
sort silent)
|
|
||||||
"Add PACKAGE (and optionally suffix -VERSION) to the cabal
|
|
||||||
file. Prompts the user before doing so.
|
|
||||||
|
|
||||||
If VERSION is non-nil it will be appended as a minimum version.
|
|
||||||
If NO-PROMPT is nil the minimum-version is read from the minibuffer
|
|
||||||
When SORT is non-nil the package entries are sorted afterwards
|
|
||||||
If SILENT ist nil the user is prompted for each source-section
|
|
||||||
"
|
|
||||||
(interactive
|
|
||||||
(list (read-from-minibuffer "Package entry: ")
|
|
||||||
nil t t nil))
|
|
||||||
(save-window-excursion
|
|
||||||
(find-file-other-window (haskell-cabal-find-file))
|
|
||||||
(let ((entry (if no-prompt package
|
|
||||||
(read-from-minibuffer
|
|
||||||
"Package entry: "
|
|
||||||
(concat package (if version (concat " >= " version) ""))))))
|
|
||||||
(haskell-cabal-add-build-dependency entry sort silent)
|
|
||||||
(when (or silent (y-or-n-p "Save cabal file?"))
|
|
||||||
(save-buffer)))))
|
|
||||||
|
|
||||||
(provide 'haskell-cabal)
|
|
||||||
|
|
||||||
;;; haskell-cabal.el ends here
|
|
Binary file not shown.
@@ -1,177 +0,0 @@
|
|||||||
;;; haskell-checkers.el --- Emacs interface to haskell lint and style checkers
|
|
||||||
|
|
||||||
;; Copyright (C) 2009-2011 Alex Ott, Liam O'Reilly
|
|
||||||
;;
|
|
||||||
;; Author: Alex Ott <alexott@gmail.com>, Liam O'Reilly <csliam@swansea.ac.uk>
|
|
||||||
;; Keywords: haskell, lint, hlint, style scanner
|
|
||||||
;; Requirements: hlint, scan, haskell
|
|
||||||
|
|
||||||
;; 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 2 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'compile)
|
|
||||||
|
|
||||||
(defgroup haskell-checkers nil
|
|
||||||
"Run HLint as inferior of Emacs, parse error messages."
|
|
||||||
:group 'tools
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defcustom hs-lint-command "hlint"
|
|
||||||
"The default lint command for \\[hlint]."
|
|
||||||
:type 'string
|
|
||||||
:group 'haskell-checkers)
|
|
||||||
|
|
||||||
(defcustom hs-scan-command "scan"
|
|
||||||
"The default scan command for \\[hs-scan]."
|
|
||||||
:type 'string
|
|
||||||
:group 'haskell-checkers)
|
|
||||||
|
|
||||||
(defcustom hs-scan-options ""
|
|
||||||
"The default options for \\[hs-scan]."
|
|
||||||
:type 'string
|
|
||||||
:group 'haskell-checkers)
|
|
||||||
|
|
||||||
(defcustom hs-lint-options ""
|
|
||||||
"The default options for \\[hlint]."
|
|
||||||
:type 'string
|
|
||||||
:group 'haskell-checkers)
|
|
||||||
|
|
||||||
(defcustom hs-checkers-save-files t
|
|
||||||
"Save modified files when run checker or not (ask user)"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-checkers)
|
|
||||||
|
|
||||||
(defcustom hs-checkers-replace-with-suggestions nil
|
|
||||||
"Replace user's code with suggested replacements (hlint only)"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-checkers)
|
|
||||||
|
|
||||||
(defcustom hs-checkers-replace-without-ask nil
|
|
||||||
"Replace user's code with suggested replacements automatically (hlint only)"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-checkers)
|
|
||||||
|
|
||||||
;; regex for replace HLint's suggestions
|
|
||||||
;;
|
|
||||||
;; ^\(.*?\):\([0-9]+\):\([0-9]+\): .*
|
|
||||||
;; Found:
|
|
||||||
;; \s +\(.*\)
|
|
||||||
;; Why not:
|
|
||||||
;; \s +\(.*\)
|
|
||||||
|
|
||||||
(defvar hs-lint-regex
|
|
||||||
"^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Why not:[\n\C-m]\\s +\\(.*\\)[\n\C-m]"
|
|
||||||
"Regex for HLint messages")
|
|
||||||
|
|
||||||
(defun hs-checkers-make-short-string (str maxlen)
|
|
||||||
(if (< (length str) maxlen)
|
|
||||||
str
|
|
||||||
(concat (substring str 0 (- maxlen 3)) "...")))
|
|
||||||
|
|
||||||
;; TODO: check, is it possible to adopt it for hs-scan?
|
|
||||||
(defun hs-lint-replace-suggestions ()
|
|
||||||
"Perform actual replacement of HLint's suggestions"
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (re-search-forward hs-lint-regex nil t)
|
|
||||||
(let* ((fname (match-string 1))
|
|
||||||
(fline (string-to-number (match-string 2)))
|
|
||||||
(old-code (match-string 4))
|
|
||||||
(new-code (match-string 5))
|
|
||||||
(msg (concat "Replace '" (hs-checkers-make-short-string old-code 30)
|
|
||||||
"' with '" (hs-checkers-make-short-string new-code 30) "'"))
|
|
||||||
(bline 0)
|
|
||||||
(eline 0)
|
|
||||||
(spos 0)
|
|
||||||
(new-old-code ""))
|
|
||||||
(save-excursion
|
|
||||||
(switch-to-buffer (get-file-buffer fname))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- fline))
|
|
||||||
(beginning-of-line)
|
|
||||||
(setq bline (point))
|
|
||||||
(when (or hs-checkers-replace-without-ask
|
|
||||||
(yes-or-no-p msg))
|
|
||||||
(end-of-line)
|
|
||||||
(setq eline (point))
|
|
||||||
(beginning-of-line)
|
|
||||||
(setq old-code (regexp-quote old-code))
|
|
||||||
(while (string-match "\\\\ " old-code spos)
|
|
||||||
(setq new-old-code (concat new-old-code
|
|
||||||
(substring old-code spos (match-beginning 0))
|
|
||||||
"\\ *"))
|
|
||||||
(setq spos (match-end 0)))
|
|
||||||
(setq new-old-code (concat new-old-code (substring old-code spos)))
|
|
||||||
(remove-text-properties bline eline '(composition nil))
|
|
||||||
(when (re-search-forward new-old-code eline t)
|
|
||||||
(replace-match new-code nil t)))))))
|
|
||||||
|
|
||||||
(defun hs-lint-finish-hook (buf msg)
|
|
||||||
"Function, that is executed at the end of HLint or scan execution"
|
|
||||||
(if hs-checkers-replace-with-suggestions
|
|
||||||
(hs-lint-replace-suggestions)
|
|
||||||
(next-error 1 t)))
|
|
||||||
|
|
||||||
(defun hs-scan-finish-hook (buf msg)
|
|
||||||
"Function, that is executed at the end of hs-scan execution"
|
|
||||||
(next-error 1 t))
|
|
||||||
|
|
||||||
(defun hs-scan-make-command (file)
|
|
||||||
"Generates command line for scan"
|
|
||||||
(concat hs-scan-command " " hs-scan-options " \"" file "\""))
|
|
||||||
|
|
||||||
(defun hs-lint-make-command (file)
|
|
||||||
"Generates command line for scan"
|
|
||||||
(concat hs-lint-command " \"" file "\"" " " hs-lint-options))
|
|
||||||
|
|
||||||
(defmacro hs-checkers-setup (type name)
|
|
||||||
"Performs setup of corresponding checker. Receives two arguments:
|
|
||||||
type - checker's type (lint or scan) that is expanded into functions and hooks names
|
|
||||||
name - user visible name for this mode"
|
|
||||||
(let ((nm (concat "hs-" (symbol-name type))))
|
|
||||||
`(progn
|
|
||||||
;;;###autoload
|
|
||||||
(defvar ,(intern (concat nm "-setup-hook")) nil
|
|
||||||
,(concat "Hook, that will executed before running " name))
|
|
||||||
(defun ,(intern (concat nm "-process-setup")) ()
|
|
||||||
"Setup compilation variables and buffer for `hlint'."
|
|
||||||
(run-hooks ',(intern (concat nm "-setup-hook"))))
|
|
||||||
;;;###autoload
|
|
||||||
(define-compilation-mode ,(intern (concat nm "-mode")) ,name
|
|
||||||
,(concat "Mode to check Haskell source code using " name)
|
|
||||||
(set (make-local-variable 'compilation-process-setup-function)
|
|
||||||
',(intern (concat nm "-process-setup")))
|
|
||||||
(set (make-local-variable 'compilation-disable-input) t)
|
|
||||||
(set (make-local-variable 'compilation-scroll-output) nil)
|
|
||||||
(set (make-local-variable 'compilation-finish-functions)
|
|
||||||
(list ',(intern (concat nm "-finish-hook")))))
|
|
||||||
;;;###autoload
|
|
||||||
(defun ,(intern nm) ()
|
|
||||||
,(concat "Run " name " for current buffer with haskell source")
|
|
||||||
(interactive)
|
|
||||||
(save-some-buffers hs-checkers-save-files)
|
|
||||||
(compilation-start (,(intern (concat nm "-make-command")) buffer-file-name)
|
|
||||||
',(intern (concat nm "-mode")))))
|
|
||||||
))
|
|
||||||
|
|
||||||
(hs-checkers-setup lint "HLint")
|
|
||||||
(hs-checkers-setup scan "HScan")
|
|
||||||
|
|
||||||
(provide 'haskell-checkers)
|
|
||||||
|
|
||||||
;;; haskell-checkers.el ends here
|
|
Binary file not shown.
@@ -1,65 +0,0 @@
|
|||||||
;;; haskell-collapse.el --- Collapse expressions
|
|
||||||
|
|
||||||
;; Copyright (c) 2014 Chris Done. All rights reserved.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(define-button-type 'haskell-collapse-toggle-button
|
|
||||||
'action 'haskell-collapse-toggle-button-callback
|
|
||||||
'follow-link t
|
|
||||||
'help-echo "Click to expand…")
|
|
||||||
|
|
||||||
(defun haskell-collapse (beg end)
|
|
||||||
"Collapse."
|
|
||||||
(interactive "r")
|
|
||||||
(goto-char end)
|
|
||||||
(let ((break nil))
|
|
||||||
(while (and (not break)
|
|
||||||
(search-backward-regexp "[[({]" beg t 1))
|
|
||||||
(unless (elt (syntax-ppss) 3)
|
|
||||||
(let ((orig (point)))
|
|
||||||
(haskell-collapse-sexp)
|
|
||||||
(goto-char orig)
|
|
||||||
(forward-char -1)
|
|
||||||
(when (= (point) orig)
|
|
||||||
(setq break t)))))))
|
|
||||||
|
|
||||||
(defun haskell-collapse-sexp ()
|
|
||||||
"Collapse the sexp starting at point."
|
|
||||||
(let ((beg (point)))
|
|
||||||
(forward-sexp)
|
|
||||||
(let ((end (point)))
|
|
||||||
(let ((o (make-overlay beg end)))
|
|
||||||
(overlay-put o 'invisible t)
|
|
||||||
(let ((start (point)))
|
|
||||||
(insert "…")
|
|
||||||
(let ((button (make-text-button start (point)
|
|
||||||
:type 'haskell-collapse-toggle-button)))
|
|
||||||
(button-put button 'overlay o)
|
|
||||||
(button-put button 'hide-on-click t)))))))
|
|
||||||
|
|
||||||
(defun haskell-collapse-toggle-button-callback (btn)
|
|
||||||
"The callback to toggle the overlay visibility."
|
|
||||||
(let ((overlay (button-get btn 'overlay)))
|
|
||||||
(when overlay
|
|
||||||
(overlay-put overlay
|
|
||||||
'invisible
|
|
||||||
(not (overlay-get overlay
|
|
||||||
'invisible)))))
|
|
||||||
(button-put btn 'invisible t)
|
|
||||||
(delete-region (button-start btn) (button-end btn)))
|
|
||||||
|
|
||||||
(provide 'haskell-collapse)
|
|
Binary file not shown.
@@ -1,825 +0,0 @@
|
|||||||
;;; haskell-commands.el --- Commands that can be run on the process
|
|
||||||
|
|
||||||
;; Copyright (c) 2014 Chris Done. All rights reserved.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'etags)
|
|
||||||
(require 'haskell-compat)
|
|
||||||
(require 'haskell-process)
|
|
||||||
(require 'haskell-font-lock)
|
|
||||||
(require 'haskell-interactive-mode)
|
|
||||||
(require 'haskell-session)
|
|
||||||
(require 'highlight-uses-mode)
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-restart ()
|
|
||||||
"Restart the inferior Haskell process."
|
|
||||||
(interactive)
|
|
||||||
(haskell-process-reset (haskell-interactive-process))
|
|
||||||
(haskell-process-set (haskell-interactive-process) 'command-queue nil)
|
|
||||||
(haskell-process-start (haskell-interactive-session)))
|
|
||||||
|
|
||||||
(defun haskell-process-start (session)
|
|
||||||
"Start the inferior Haskell process."
|
|
||||||
(let ((existing-process (get-process (haskell-session-name (haskell-interactive-session)))))
|
|
||||||
(when (processp existing-process)
|
|
||||||
(haskell-interactive-mode-echo session "Restarting process ...")
|
|
||||||
(haskell-process-set (haskell-session-process session) 'is-restarting t)
|
|
||||||
(delete-process existing-process)))
|
|
||||||
(let ((process (or (haskell-session-process session)
|
|
||||||
(haskell-process-make (haskell-session-name session))))
|
|
||||||
(old-queue (haskell-process-get (haskell-session-process session)
|
|
||||||
'command-queue)))
|
|
||||||
(haskell-session-set-process session process)
|
|
||||||
(haskell-process-set-session process session)
|
|
||||||
(haskell-process-set-cmd process nil)
|
|
||||||
(haskell-process-set (haskell-session-process session) 'is-restarting nil)
|
|
||||||
(let ((default-directory (haskell-session-cabal-dir session))
|
|
||||||
(log-and-command (haskell-process-compute-process-log-and-command session (haskell-process-type))))
|
|
||||||
(haskell-session-pwd session)
|
|
||||||
(haskell-process-set-process
|
|
||||||
process
|
|
||||||
(progn
|
|
||||||
(haskell-process-log (propertize (format "%S" log-and-command)))
|
|
||||||
(apply #'start-process (cdr log-and-command)))))
|
|
||||||
(progn (set-process-sentinel (haskell-process-process process) 'haskell-process-sentinel)
|
|
||||||
(set-process-filter (haskell-process-process process) 'haskell-process-filter))
|
|
||||||
(haskell-process-send-startup process)
|
|
||||||
(unless (eq 'cabal-repl (haskell-process-type)) ;; "cabal repl" sets the proper CWD
|
|
||||||
(haskell-process-change-dir session
|
|
||||||
process
|
|
||||||
(haskell-session-current-dir session)))
|
|
||||||
(haskell-process-set process 'command-queue
|
|
||||||
(append (haskell-process-get (haskell-session-process session)
|
|
||||||
'command-queue)
|
|
||||||
old-queue))
|
|
||||||
process))
|
|
||||||
|
|
||||||
(defun haskell-process-send-startup (process)
|
|
||||||
"Send the necessary start messages."
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state process
|
|
||||||
|
|
||||||
:go (lambda (process)
|
|
||||||
(haskell-process-send-string process ":set prompt \"\\4\"")
|
|
||||||
(haskell-process-send-string process "Prelude.putStrLn \"\"")
|
|
||||||
(haskell-process-send-string process ":set -v1"))
|
|
||||||
|
|
||||||
:live (lambda (process buffer)
|
|
||||||
(when (haskell-process-consume
|
|
||||||
process
|
|
||||||
"^\*\*\* WARNING: \\(.+\\) is writable by someone else, IGNORING!$")
|
|
||||||
(let ((path (match-string 1 buffer)))
|
|
||||||
(haskell-session-modify
|
|
||||||
(haskell-process-session process)
|
|
||||||
'ignored-files
|
|
||||||
(lambda (files)
|
|
||||||
(cl-remove-duplicates (cons path files) :test 'string=)))
|
|
||||||
(haskell-interactive-mode-compile-warning
|
|
||||||
(haskell-process-session process)
|
|
||||||
(format "GHCi is ignoring: %s (run M-x haskell-process-unignore)"
|
|
||||||
path)))))
|
|
||||||
|
|
||||||
:complete (lambda (process _)
|
|
||||||
(haskell-interactive-mode-echo
|
|
||||||
(haskell-process-session process)
|
|
||||||
(concat (nth (random (length haskell-process-greetings))
|
|
||||||
haskell-process-greetings)
|
|
||||||
(when haskell-process-show-debug-tips
|
|
||||||
"
|
|
||||||
If I break, you can:
|
|
||||||
1. Restart: M-x haskell-process-restart
|
|
||||||
2. Configure logging: C-h v haskell-process-log (useful for debugging)
|
|
||||||
3. General config: M-x customize-mode
|
|
||||||
4. Hide these tips: C-h v haskell-process-show-debug-tips")))))))
|
|
||||||
|
|
||||||
(defun haskell-commands-process ()
|
|
||||||
"Get the Haskell session, throws an error if not available."
|
|
||||||
(or (haskell-session-process (haskell-session-maybe))
|
|
||||||
(error "No Haskell session/process associated with this
|
|
||||||
buffer. Maybe run M-x haskell-session-change?")))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-clear ()
|
|
||||||
"Clear the current process."
|
|
||||||
(interactive)
|
|
||||||
(haskell-process-reset (haskell-commands-process))
|
|
||||||
(haskell-process-set (haskell-commands-process) 'command-queue nil))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-interrupt ()
|
|
||||||
"Interrupt the process (SIGINT)."
|
|
||||||
(interactive)
|
|
||||||
(interrupt-process (haskell-process-process (haskell-commands-process))))
|
|
||||||
|
|
||||||
(defun haskell-process-reload-with-fbytecode (process module-buffer)
|
|
||||||
"Reload FILE-NAME with -fbyte-code set, and then restore -fobject-code."
|
|
||||||
(haskell-process-queue-without-filters process ":set -fbyte-code")
|
|
||||||
(haskell-process-touch-buffer process module-buffer)
|
|
||||||
(haskell-process-queue-without-filters process ":reload")
|
|
||||||
(haskell-process-queue-without-filters process ":set -fobject-code"))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-touch-buffer (process buffer)
|
|
||||||
"Updates mtime on the file for BUFFER by queing a touch on
|
|
||||||
PROCESS."
|
|
||||||
(interactive)
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (cons process buffer)
|
|
||||||
:go (lambda (state)
|
|
||||||
(haskell-process-send-string
|
|
||||||
(car state)
|
|
||||||
(format ":!%s %s"
|
|
||||||
"touch"
|
|
||||||
(shell-quote-argument (buffer-file-name
|
|
||||||
(cdr state))))))
|
|
||||||
:complete (lambda (state _)
|
|
||||||
(with-current-buffer (cdr state)
|
|
||||||
(clear-visited-file-modtime))))))
|
|
||||||
|
|
||||||
(defvar url-http-response-status)
|
|
||||||
(defvar url-http-end-of-headers)
|
|
||||||
|
|
||||||
(defun haskell-process-hayoo-ident (ident)
|
|
||||||
"Hayoo for IDENT, returns a list of modules asyncronously through CALLBACK."
|
|
||||||
;; We need a real/simulated closure, because otherwise these
|
|
||||||
;; variables will be unbound when the url-retrieve callback is
|
|
||||||
;; called.
|
|
||||||
;; TODO: Remove when this code is converted to lexical bindings by
|
|
||||||
;; default (Emacs 24.1+)
|
|
||||||
(let ((url (format haskell-process-hayoo-query-url (url-hexify-string ident))))
|
|
||||||
(with-current-buffer (url-retrieve-synchronously url)
|
|
||||||
(if (= 200 url-http-response-status)
|
|
||||||
(progn
|
|
||||||
(goto-char url-http-end-of-headers)
|
|
||||||
(let* ((res (json-read))
|
|
||||||
(results (assoc-default 'result res)))
|
|
||||||
;; TODO: gather packages as well, and when we choose a
|
|
||||||
;; given import, check that we have the package in the
|
|
||||||
;; cabal file as well.
|
|
||||||
(cl-mapcan (lambda (r)
|
|
||||||
;; append converts from vector -> list
|
|
||||||
(append (assoc-default 'resultModules r) nil))
|
|
||||||
results)))
|
|
||||||
(warn "HTTP error %s fetching %s" url-http-response-status url)))))
|
|
||||||
|
|
||||||
(defun haskell-process-hoogle-ident (ident)
|
|
||||||
"Hoogle for IDENT, returns a list of modules."
|
|
||||||
(with-temp-buffer
|
|
||||||
(let ((hoogle-error (call-process "hoogle" nil t nil "search" "--exact" ident)))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(unless (or (/= 0 hoogle-error)
|
|
||||||
(looking-at "^No results found")
|
|
||||||
(looking-at "^package "))
|
|
||||||
(while (re-search-forward "^\\([^ ]+\\).*$" nil t)
|
|
||||||
(replace-match "\\1" nil nil))
|
|
||||||
(cl-remove-if (lambda (a) (string= "" a))
|
|
||||||
(split-string (buffer-string)
|
|
||||||
"\n"))))))
|
|
||||||
|
|
||||||
(defun haskell-process-haskell-docs-ident (ident)
|
|
||||||
"Search with haskell-docs for IDENT, returns a list of modules."
|
|
||||||
(cl-remove-if-not (lambda (a) (string-match "^[A-Z][A-Za-b0-9_'.]+$" a))
|
|
||||||
(split-string (shell-command-to-string (concat "haskell-docs --modules " ident))
|
|
||||||
"\n")))
|
|
||||||
|
|
||||||
(defun haskell-process-import-modules (process modules)
|
|
||||||
"Import `modules' with :m +, and send any import statements
|
|
||||||
from `module-buffer'."
|
|
||||||
(when haskell-process-auto-import-loaded-modules
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (cons process modules)
|
|
||||||
:go (lambda (state)
|
|
||||||
(haskell-process-send-string
|
|
||||||
(car state)
|
|
||||||
(format ":m + %s" (mapconcat 'identity (cdr state) " "))))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-describe (ident)
|
|
||||||
"Describe the given identifier."
|
|
||||||
(interactive (list (read-from-minibuffer "Describe identifier: "
|
|
||||||
(haskell-ident-at-point))))
|
|
||||||
(let ((results (read (shell-command-to-string
|
|
||||||
(concat "haskell-docs --sexp "
|
|
||||||
ident)))))
|
|
||||||
(help-setup-xref (list #'haskell-describe ident)
|
|
||||||
(called-interactively-p 'interactive))
|
|
||||||
(save-excursion
|
|
||||||
(with-help-window (help-buffer)
|
|
||||||
(with-current-buffer (help-buffer)
|
|
||||||
(if results
|
|
||||||
(cl-loop for result in results
|
|
||||||
do (insert (propertize ident 'font-lock-face
|
|
||||||
'((:inherit font-lock-type-face
|
|
||||||
:underline t)))
|
|
||||||
" is defined in "
|
|
||||||
(let ((module (cadr (assoc 'module result))))
|
|
||||||
(if module
|
|
||||||
(concat module " ")
|
|
||||||
""))
|
|
||||||
(cadr (assoc 'package result))
|
|
||||||
"\n\n")
|
|
||||||
do (let ((type (cadr (assoc 'type result))))
|
|
||||||
(when type
|
|
||||||
(insert (haskell-fontify-as-mode type 'haskell-mode)
|
|
||||||
"\n")))
|
|
||||||
do (let ((args (cadr (assoc 'type results))))
|
|
||||||
(cl-loop for arg in args
|
|
||||||
do (insert arg "\n"))
|
|
||||||
(insert "\n"))
|
|
||||||
do (insert (cadr (assoc 'documentation result)))
|
|
||||||
do (insert "\n\n"))
|
|
||||||
(insert "No results for " ident)))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-rgrep (&optional prompt)
|
|
||||||
"Grep the effective project for the symbol at point. Very
|
|
||||||
useful for codebase navigation. Prompts for an arbitrary regexp
|
|
||||||
given a prefix arg."
|
|
||||||
(interactive "P")
|
|
||||||
(let ((sym (if prompt
|
|
||||||
(read-from-minibuffer "Look for: ")
|
|
||||||
(haskell-ident-at-point))))
|
|
||||||
(rgrep sym
|
|
||||||
"*.hs" ;; TODO: common Haskell extensions.
|
|
||||||
(haskell-session-current-dir (haskell-interactive-session)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-do-info (&optional prompt-value)
|
|
||||||
"Print info on the identifier at point.
|
|
||||||
If PROMPT-VALUE is non-nil, request identifier via mini-buffer."
|
|
||||||
(interactive "P")
|
|
||||||
(haskell-process-do-simple-echo
|
|
||||||
(let ((ident (replace-regexp-in-string
|
|
||||||
"^!\\([A-Z_a-z]\\)"
|
|
||||||
"\\1"
|
|
||||||
(if prompt-value
|
|
||||||
(read-from-minibuffer "Info: " (haskell-ident-at-point))
|
|
||||||
(haskell-ident-at-point))))
|
|
||||||
(modname (unless prompt-value
|
|
||||||
(haskell-utils-parse-import-statement-at-point))))
|
|
||||||
(if modname
|
|
||||||
(format ":browse! %s" modname)
|
|
||||||
(format (if (string-match "^[a-zA-Z_]" ident)
|
|
||||||
":info %s"
|
|
||||||
":info (%s)")
|
|
||||||
(or ident
|
|
||||||
(haskell-ident-at-point)))))
|
|
||||||
'haskell-mode))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-do-type (&optional insert-value)
|
|
||||||
"Print the type of the given expression."
|
|
||||||
(interactive "P")
|
|
||||||
(if insert-value
|
|
||||||
(haskell-process-insert-type)
|
|
||||||
(haskell-process-do-simple-echo
|
|
||||||
(let ((ident (haskell-ident-at-point)))
|
|
||||||
;; TODO: Generalize all these `string-match' of ident calls into
|
|
||||||
;; one function.
|
|
||||||
(format (if (string-match "^[_[:lower:][:upper:]]" ident)
|
|
||||||
":type %s"
|
|
||||||
":type (%s)")
|
|
||||||
ident))
|
|
||||||
'haskell-mode)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-mode-jump-to-def-or-tag (&optional next-p)
|
|
||||||
"Jump to the definition (by consulting GHCi), or (fallback)
|
|
||||||
jump to the tag.
|
|
||||||
|
|
||||||
Remember: If GHCi is busy doing something, this will delay, but
|
|
||||||
it will always be accurate, in contrast to tags, which always
|
|
||||||
work but are not always accurate.
|
|
||||||
If the definition or tag is found, the location from which you jumped
|
|
||||||
will be pushed onto `xref--marker-ring', so you can return to that
|
|
||||||
position with `xref-pop-marker-stack'."
|
|
||||||
(interactive "P")
|
|
||||||
(let ((initial-loc (point-marker))
|
|
||||||
(loc (haskell-mode-find-def (haskell-ident-at-point))))
|
|
||||||
(if loc
|
|
||||||
(haskell-mode-handle-generic-loc loc)
|
|
||||||
(call-interactively 'haskell-mode-tag-find))
|
|
||||||
(unless (equal initial-loc (point-marker))
|
|
||||||
(save-excursion
|
|
||||||
(goto-char initial-loc)
|
|
||||||
(set-mark-command nil)
|
|
||||||
;; Store position for return with `xref-pop-marker-stack'
|
|
||||||
(xref-push-marker-stack)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-mode-goto-loc ()
|
|
||||||
"Go to the location of the thing at point. Requires the :loc-at
|
|
||||||
command from GHCi."
|
|
||||||
(interactive)
|
|
||||||
(let ((loc (haskell-mode-loc-at)))
|
|
||||||
(when loc
|
|
||||||
(haskell-mode-goto-span loc))))
|
|
||||||
|
|
||||||
(defun haskell-mode-goto-span (span)
|
|
||||||
"Jump to the span, whatever file and line and column it needs
|
|
||||||
to to get there."
|
|
||||||
(xref-push-marker-stack)
|
|
||||||
(find-file (expand-file-name (plist-get span :path)
|
|
||||||
(haskell-session-cabal-dir (haskell-interactive-session))))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- (plist-get span :start-line)))
|
|
||||||
(forward-char (plist-get span :start-col)))
|
|
||||||
|
|
||||||
(defun haskell-process-insert-type ()
|
|
||||||
"Get the identifer at the point and insert its type, if
|
|
||||||
possible, using GHCi's :type."
|
|
||||||
(let ((process (haskell-interactive-process))
|
|
||||||
(query (let ((ident (haskell-ident-at-point)))
|
|
||||||
(format (if (string-match "^[_[:lower:][:upper:]]" ident)
|
|
||||||
":type %s"
|
|
||||||
":type (%s)")
|
|
||||||
ident))))
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (list process query (current-buffer))
|
|
||||||
:go (lambda (state)
|
|
||||||
(haskell-process-send-string (nth 0 state)
|
|
||||||
(nth 1 state)))
|
|
||||||
:complete (lambda (state response)
|
|
||||||
(cond
|
|
||||||
;; TODO: Generalize this into a function.
|
|
||||||
((or (string-match "^Top level" response)
|
|
||||||
(string-match "^<interactive>" response))
|
|
||||||
(message response))
|
|
||||||
(t
|
|
||||||
(with-current-buffer (nth 2 state)
|
|
||||||
(goto-char (line-beginning-position))
|
|
||||||
(insert (format "%s\n" (replace-regexp-in-string "\n$" "" response)))))))))))
|
|
||||||
|
|
||||||
(defun haskell-mode-find-def (ident)
|
|
||||||
"Find definition location of identifier. Uses the GHCi process
|
|
||||||
to find the location.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
(library <package> <module>)
|
|
||||||
(file <path> <line> <col>)
|
|
||||||
(module <name>)
|
|
||||||
"
|
|
||||||
(let ((reply (haskell-process-queue-sync-request
|
|
||||||
(haskell-interactive-process)
|
|
||||||
(format (if (string-match "^[a-zA-Z_]" ident)
|
|
||||||
":info %s"
|
|
||||||
":info (%s)")
|
|
||||||
ident))))
|
|
||||||
(let ((match (string-match "-- Defined \\(at\\|in\\) \\(.+\\)$" reply)))
|
|
||||||
(when match
|
|
||||||
(let ((defined (match-string 2 reply)))
|
|
||||||
(let ((match (string-match "\\(.+?\\):\\([0-9]+\\):\\([0-9]+\\)$" defined)))
|
|
||||||
(cond
|
|
||||||
(match
|
|
||||||
(list 'file
|
|
||||||
(expand-file-name (match-string 1 defined)
|
|
||||||
(haskell-session-current-dir (haskell-interactive-session)))
|
|
||||||
(string-to-number (match-string 2 defined))
|
|
||||||
(string-to-number (match-string 3 defined))))
|
|
||||||
(t
|
|
||||||
(let ((match (string-match "`\\(.+?\\):\\(.+?\\)'$" defined)))
|
|
||||||
(if match
|
|
||||||
(list 'library
|
|
||||||
(match-string 1 defined)
|
|
||||||
(match-string 2 defined))
|
|
||||||
(let ((match (string-match "`\\(.+?\\)'$" defined)))
|
|
||||||
(if match
|
|
||||||
(list 'module
|
|
||||||
(match-string 1 defined))))))))))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-mode-jump-to-def (ident)
|
|
||||||
"Jump to definition of identifier at point."
|
|
||||||
(interactive (list (haskell-ident-at-point)))
|
|
||||||
(let ((loc (haskell-mode-find-def ident)))
|
|
||||||
(when loc
|
|
||||||
(haskell-mode-handle-generic-loc loc))))
|
|
||||||
|
|
||||||
(defun haskell-mode-handle-generic-loc (loc)
|
|
||||||
"Either jump to or display a generic location. Either a file or
|
|
||||||
a library."
|
|
||||||
(cl-case (car loc)
|
|
||||||
(file (haskell-mode-jump-to-loc (cdr loc)))
|
|
||||||
(library (message "Defined in `%s' (%s)."
|
|
||||||
(elt loc 2)
|
|
||||||
(elt loc 1)))
|
|
||||||
(module (message "Defined in `%s'."
|
|
||||||
(elt loc 1)))))
|
|
||||||
|
|
||||||
(defun haskell-mode-loc-at ()
|
|
||||||
"Get the location at point. Requires the :loc-at command from
|
|
||||||
GHCi."
|
|
||||||
(let ((pos (or (when (region-active-p)
|
|
||||||
(cons (region-beginning)
|
|
||||||
(region-end)))
|
|
||||||
(haskell-spanable-pos-at-point)
|
|
||||||
(cons (point)
|
|
||||||
(point)))))
|
|
||||||
(when pos
|
|
||||||
(let ((reply (haskell-process-queue-sync-request
|
|
||||||
(haskell-interactive-process)
|
|
||||||
(save-excursion
|
|
||||||
(format ":loc-at %s %d %d %d %d %s"
|
|
||||||
(buffer-file-name)
|
|
||||||
(progn (goto-char (car pos))
|
|
||||||
(line-number-at-pos))
|
|
||||||
(1+ (current-column)) ;; GHC uses 1-based columns.
|
|
||||||
(progn (goto-char (cdr pos))
|
|
||||||
(line-number-at-pos))
|
|
||||||
(1+ (current-column)) ;; GHC uses 1-based columns.
|
|
||||||
(buffer-substring-no-properties (car pos)
|
|
||||||
(cdr pos)))))))
|
|
||||||
(if reply
|
|
||||||
(if (string-match "\\(.*?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))"
|
|
||||||
reply)
|
|
||||||
(list :path (match-string 1 reply)
|
|
||||||
:start-line (string-to-number (match-string 2 reply))
|
|
||||||
;; ;; GHC uses 1-based columns.
|
|
||||||
:start-col (1- (string-to-number (match-string 3 reply)))
|
|
||||||
:end-line (string-to-number (match-string 4 reply))
|
|
||||||
;; GHC uses 1-based columns.
|
|
||||||
:end-col (1- (string-to-number (match-string 5 reply))))
|
|
||||||
(error (propertize reply 'face 'compilation-error)))
|
|
||||||
(error (propertize "No reply. Is :loc-at supported?"
|
|
||||||
'face 'compilation-error)))))))
|
|
||||||
|
|
||||||
(defun haskell-mode-type-at ()
|
|
||||||
"Get the type of the thing at point. Requires the :type-at
|
|
||||||
command from GHCi."
|
|
||||||
(let ((pos (or (when (region-active-p)
|
|
||||||
(cons (region-beginning)
|
|
||||||
(region-end)))
|
|
||||||
(haskell-spanable-pos-at-point)
|
|
||||||
(cons (point)
|
|
||||||
(point)))))
|
|
||||||
(when pos
|
|
||||||
(replace-regexp-in-string
|
|
||||||
"\n$"
|
|
||||||
""
|
|
||||||
(save-excursion
|
|
||||||
(haskell-process-queue-sync-request
|
|
||||||
(haskell-interactive-process)
|
|
||||||
(replace-regexp-in-string
|
|
||||||
"\n"
|
|
||||||
" "
|
|
||||||
(format ":type-at %s %d %d %d %d %s"
|
|
||||||
(buffer-file-name)
|
|
||||||
(progn (goto-char (car pos))
|
|
||||||
(line-number-at-pos))
|
|
||||||
(1+ (current-column))
|
|
||||||
(progn (goto-char (cdr pos))
|
|
||||||
(line-number-at-pos))
|
|
||||||
(1+ (current-column))
|
|
||||||
(buffer-substring-no-properties (car pos)
|
|
||||||
(cdr pos))))))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-cd (&optional not-interactive)
|
|
||||||
"Change directory."
|
|
||||||
(interactive)
|
|
||||||
(let* ((session (haskell-interactive-session))
|
|
||||||
(dir (haskell-session-pwd session t)))
|
|
||||||
(haskell-process-log
|
|
||||||
(propertize (format "Changing directory to %s ...\n" dir)
|
|
||||||
'face font-lock-comment-face))
|
|
||||||
(haskell-process-change-dir session
|
|
||||||
(haskell-interactive-process)
|
|
||||||
dir)))
|
|
||||||
|
|
||||||
(defun haskell-session-pwd (session &optional change)
|
|
||||||
"Prompt for the current directory."
|
|
||||||
(or (unless change
|
|
||||||
(haskell-session-get session 'current-dir))
|
|
||||||
(progn (haskell-session-set-current-dir
|
|
||||||
session
|
|
||||||
(haskell-utils-read-directory-name
|
|
||||||
(if change "Change directory: " "Set current directory: ")
|
|
||||||
(or (haskell-session-get session 'current-dir)
|
|
||||||
(haskell-session-get session 'cabal-dir)
|
|
||||||
(if (buffer-file-name)
|
|
||||||
(file-name-directory (buffer-file-name))
|
|
||||||
"~/"))))
|
|
||||||
(haskell-session-get session 'current-dir))))
|
|
||||||
|
|
||||||
(defun haskell-process-change-dir (session process dir)
|
|
||||||
"Change the directory of the current process."
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (list session process dir)
|
|
||||||
:go
|
|
||||||
(lambda (state)
|
|
||||||
(haskell-process-send-string
|
|
||||||
(cadr state) (format ":cd %s" (cl-caddr state))))
|
|
||||||
|
|
||||||
:complete
|
|
||||||
(lambda (state _)
|
|
||||||
(haskell-session-set-current-dir (car state) (cl-caddr state))
|
|
||||||
(haskell-interactive-mode-echo (car state)
|
|
||||||
(format "Changed directory: %s"
|
|
||||||
(cl-caddr state)))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-cabal-macros ()
|
|
||||||
"Send the cabal macros string."
|
|
||||||
(interactive)
|
|
||||||
(haskell-process-queue-without-filters (haskell-interactive-process)
|
|
||||||
":set -optP-include -optPdist/build/autogen/cabal_macros.h"))
|
|
||||||
|
|
||||||
(defun haskell-process-do-try-info (sym)
|
|
||||||
"Get info of `sym' and echo in the minibuffer."
|
|
||||||
(let ((process (haskell-interactive-process)))
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (cons process sym)
|
|
||||||
:go (lambda (state)
|
|
||||||
(haskell-process-send-string
|
|
||||||
(car state)
|
|
||||||
(if (string-match "^[A-Za-z_]" (cdr state))
|
|
||||||
(format ":info %s" (cdr state))
|
|
||||||
(format ":info (%s)" (cdr state)))))
|
|
||||||
:complete (lambda (state response)
|
|
||||||
(unless (or (string-match "^Top level" response)
|
|
||||||
(string-match "^<interactive>" response))
|
|
||||||
(haskell-mode-message-line response)))))))
|
|
||||||
|
|
||||||
(defun haskell-process-do-try-type (sym)
|
|
||||||
"Get type of `sym' and echo in the minibuffer."
|
|
||||||
(let ((process (haskell-interactive-process)))
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (cons process sym)
|
|
||||||
:go (lambda (state)
|
|
||||||
(haskell-process-send-string
|
|
||||||
(car state)
|
|
||||||
(if (string-match "^[A-Za-z_]" (cdr state))
|
|
||||||
(format ":type %s" (cdr state))
|
|
||||||
(format ":type (%s)" (cdr state)))))
|
|
||||||
:complete (lambda (state response)
|
|
||||||
(unless (or (string-match "^Top level" response)
|
|
||||||
(string-match "^<interactive>" response))
|
|
||||||
(haskell-mode-message-line response)))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-mode-show-type-at (&optional insert-value)
|
|
||||||
"Show the type of the thing at point."
|
|
||||||
(interactive "P")
|
|
||||||
(let ((ty (haskell-mode-type-at))
|
|
||||||
(orig (point)))
|
|
||||||
(if insert-value
|
|
||||||
(let ((ident-pos (haskell-ident-pos-at-point)))
|
|
||||||
(cond
|
|
||||||
((region-active-p)
|
|
||||||
(delete-region (region-beginning)
|
|
||||||
(region-end))
|
|
||||||
(insert "(" ty ")")
|
|
||||||
(goto-char (1+ orig)))
|
|
||||||
((= (line-beginning-position) (car ident-pos))
|
|
||||||
(goto-char (line-beginning-position))
|
|
||||||
(insert (haskell-fontify-as-mode ty 'haskell-mode)
|
|
||||||
"\n"))
|
|
||||||
(t
|
|
||||||
(save-excursion
|
|
||||||
(let ((col (save-excursion (goto-char (car ident-pos))
|
|
||||||
(current-column))))
|
|
||||||
(save-excursion (insert "\n")
|
|
||||||
(indent-to col))
|
|
||||||
(insert (haskell-fontify-as-mode ty 'haskell-mode)))))))
|
|
||||||
(message "%s" (haskell-fontify-as-mode ty 'haskell-mode)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-generate-tags (&optional and-then-find-this-tag)
|
|
||||||
"Regenerate the TAGS table."
|
|
||||||
(interactive)
|
|
||||||
(let ((process (haskell-interactive-process)))
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (cons process and-then-find-this-tag)
|
|
||||||
:go (lambda (state)
|
|
||||||
(if (eq system-type 'windows-nt)
|
|
||||||
(haskell-process-send-string
|
|
||||||
(car state)
|
|
||||||
(format ":!powershell -Command \"& { cd %s ; hasktags -e -x (ls -fi *.hs *.lhs *.hsc -exclude \\\"#*#\\\" -name -r) ; exit }\""
|
|
||||||
(haskell-session-cabal-dir
|
|
||||||
(haskell-process-session (car state)))))
|
|
||||||
(haskell-process-send-string
|
|
||||||
(car state)
|
|
||||||
(format ":!cd %s && %s | %s"
|
|
||||||
(haskell-session-cabal-dir
|
|
||||||
(haskell-process-session (car state)))
|
|
||||||
"find . -name '*.hs' -print0 -or -name '*.lhs' -print0 -or -name '*.hsc' -print0"
|
|
||||||
"xargs -0 hasktags -e -x"))))
|
|
||||||
:complete (lambda (state response)
|
|
||||||
(when (cdr state)
|
|
||||||
(let ((tags-file-name
|
|
||||||
(haskell-session-tags-filename
|
|
||||||
(haskell-process-session (car state)))))
|
|
||||||
(find-tag (cdr state))))
|
|
||||||
(haskell-mode-message-line "Tags generated."))))))
|
|
||||||
|
|
||||||
(defun haskell-process-add-cabal-autogen ()
|
|
||||||
"Add <cabal-project-dir>/dist/build/autogen/ to the ghci search
|
|
||||||
path. This allows modules such as 'Path_...', generated by cabal,
|
|
||||||
to be loaded by ghci."
|
|
||||||
(unless (eq 'cabal-repl (haskell-process-type)) ;; redundant with "cabal repl"
|
|
||||||
(let*
|
|
||||||
((session (haskell-interactive-session))
|
|
||||||
(cabal-dir (haskell-session-cabal-dir session))
|
|
||||||
(ghci-gen-dir (format "%sdist/build/autogen/" cabal-dir)))
|
|
||||||
(haskell-process-queue-without-filters
|
|
||||||
(haskell-interactive-process)
|
|
||||||
(format ":set -i%s" ghci-gen-dir)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-unignore ()
|
|
||||||
"Unignore any files that were specified as being ignored by the
|
|
||||||
inferior GHCi process."
|
|
||||||
(interactive)
|
|
||||||
(let ((session (haskell-interactive-session))
|
|
||||||
(changed nil))
|
|
||||||
(if (null (haskell-session-get session
|
|
||||||
'ignored-files))
|
|
||||||
(message "Nothing to unignore!")
|
|
||||||
(cl-loop for file in (haskell-session-get session
|
|
||||||
'ignored-files)
|
|
||||||
do (cl-case (read-event
|
|
||||||
(propertize (format "Set permissions? %s (y, n, v: stop and view file)"
|
|
||||||
file)
|
|
||||||
'face 'minibuffer-prompt))
|
|
||||||
(?y
|
|
||||||
(haskell-process-unignore-file session file)
|
|
||||||
(setq changed t))
|
|
||||||
(?v
|
|
||||||
(find-file file)
|
|
||||||
(cl-return))))
|
|
||||||
(when (and changed
|
|
||||||
(y-or-n-p "Restart GHCi process now? "))
|
|
||||||
(haskell-process-restart)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-session-change-target (target)
|
|
||||||
"Set the build target for cabal repl"
|
|
||||||
(interactive "sNew build target:")
|
|
||||||
(let* ((session haskell-session)
|
|
||||||
(old-target (haskell-session-get session 'target)))
|
|
||||||
(when session
|
|
||||||
(haskell-session-set-target session target)
|
|
||||||
(when (and (not (string= old-target target))
|
|
||||||
(y-or-n-p "Target changed, restart haskell process?"))
|
|
||||||
(haskell-process-start session)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-mode-stylish-buffer ()
|
|
||||||
"Apply stylish-haskell to the current buffer."
|
|
||||||
(interactive)
|
|
||||||
(let ((column (current-column))
|
|
||||||
(line (line-number-at-pos)))
|
|
||||||
(haskell-mode-buffer-apply-command "stylish-haskell")
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- line))
|
|
||||||
(goto-char (+ column (point)))))
|
|
||||||
|
|
||||||
(defun haskell-mode-buffer-apply-command (cmd)
|
|
||||||
"Execute shell command CMD with current buffer as input and
|
|
||||||
replace the whole buffer with the output. If CMD fails the buffer
|
|
||||||
remains unchanged."
|
|
||||||
(set-buffer-modified-p t)
|
|
||||||
(let* ((chomp (lambda (str)
|
|
||||||
(while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'" str)
|
|
||||||
(setq str (replace-match "" t t str)))
|
|
||||||
str))
|
|
||||||
(errout (lambda (fmt &rest args)
|
|
||||||
(let* ((warning-fill-prefix " "))
|
|
||||||
(display-warning cmd (apply 'format fmt args) :warning))))
|
|
||||||
(filename (buffer-file-name (current-buffer)))
|
|
||||||
(cmd-prefix (replace-regexp-in-string " .*" "" cmd))
|
|
||||||
(tmp-file (make-temp-file cmd-prefix))
|
|
||||||
(err-file (make-temp-file cmd-prefix))
|
|
||||||
(default-directory (if (and (boundp 'haskell-session)
|
|
||||||
haskell-session)
|
|
||||||
(haskell-session-cabal-dir haskell-session)
|
|
||||||
default-directory))
|
|
||||||
(errcode (with-temp-file tmp-file
|
|
||||||
(call-process cmd filename
|
|
||||||
(list (current-buffer) err-file) nil)))
|
|
||||||
(stderr-output
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents err-file)
|
|
||||||
(funcall chomp (buffer-substring-no-properties (point-min) (point-max)))))
|
|
||||||
(stdout-output
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert-file-contents tmp-file)
|
|
||||||
(buffer-substring-no-properties (point-min) (point-max)))))
|
|
||||||
(if (string= "" stderr-output)
|
|
||||||
(if (string= "" stdout-output)
|
|
||||||
(funcall errout
|
|
||||||
"Error: %s produced no output, leaving buffer alone" cmd)
|
|
||||||
(save-restriction
|
|
||||||
(widen)
|
|
||||||
;; command successful, insert file with replacement to preserve
|
|
||||||
;; markers.
|
|
||||||
(insert-file-contents tmp-file nil nil nil t)))
|
|
||||||
;; non-null stderr, command must have failed
|
|
||||||
(funcall errout "%s failed: %s" cmd stderr-output))
|
|
||||||
(delete-file tmp-file)
|
|
||||||
(delete-file err-file)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-mode-find-uses ()
|
|
||||||
"Find uses of the identifier at point, highlight them all."
|
|
||||||
(interactive)
|
|
||||||
(let ((spans (haskell-mode-uses-at)))
|
|
||||||
(unless (null spans)
|
|
||||||
(highlight-uses-mode 1)
|
|
||||||
(cl-loop for span in spans
|
|
||||||
do (haskell-mode-make-use-highlight span)))))
|
|
||||||
|
|
||||||
(defun haskell-mode-make-use-highlight (span)
|
|
||||||
"Make a highlight overlay at the given span."
|
|
||||||
(save-window-excursion
|
|
||||||
(save-excursion
|
|
||||||
(haskell-mode-goto-span span)
|
|
||||||
(save-excursion
|
|
||||||
(highlight-uses-mode-highlight
|
|
||||||
(progn
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- (plist-get span :start-line)))
|
|
||||||
(forward-char (plist-get span :start-col))
|
|
||||||
(point))
|
|
||||||
(progn
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- (plist-get span :end-line)))
|
|
||||||
(forward-char (plist-get span :end-col))
|
|
||||||
(point)))))))
|
|
||||||
|
|
||||||
(defun haskell-mode-uses-at ()
|
|
||||||
"Get the locations of uses for the ident at point. Requires
|
|
||||||
the :uses command from GHCi."
|
|
||||||
(let ((pos (or (when (region-active-p)
|
|
||||||
(cons (region-beginning)
|
|
||||||
(region-end)))
|
|
||||||
(haskell-ident-pos-at-point)
|
|
||||||
(cons (point)
|
|
||||||
(point)))))
|
|
||||||
(when pos
|
|
||||||
(let ((reply (haskell-process-queue-sync-request
|
|
||||||
(haskell-interactive-process)
|
|
||||||
(save-excursion
|
|
||||||
(format ":uses %s %d %d %d %d %s"
|
|
||||||
(buffer-file-name)
|
|
||||||
(progn (goto-char (car pos))
|
|
||||||
(line-number-at-pos))
|
|
||||||
(1+ (current-column)) ;; GHC uses 1-based columns.
|
|
||||||
(progn (goto-char (cdr pos))
|
|
||||||
(line-number-at-pos))
|
|
||||||
(1+ (current-column)) ;; GHC uses 1-based columns.
|
|
||||||
(buffer-substring-no-properties (car pos)
|
|
||||||
(cdr pos)))))))
|
|
||||||
(if reply
|
|
||||||
(let ((lines (split-string reply "\n" t)))
|
|
||||||
(cl-remove-if
|
|
||||||
#'null
|
|
||||||
(mapcar (lambda (line)
|
|
||||||
(if (string-match "\\(.*?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))"
|
|
||||||
line)
|
|
||||||
(list :path (match-string 1 line)
|
|
||||||
:start-line (string-to-number (match-string 2 line))
|
|
||||||
;; ;; GHC uses 1-based columns.
|
|
||||||
:start-col (1- (string-to-number (match-string 3 line)))
|
|
||||||
:end-line (string-to-number (match-string 4 line))
|
|
||||||
;; GHC uses 1-based columns.
|
|
||||||
:end-col (1- (string-to-number (match-string 5 line))))
|
|
||||||
(error (propertize line 'face 'compilation-error))))
|
|
||||||
lines)))
|
|
||||||
(error (propertize "No reply. Is :uses supported?"
|
|
||||||
'face 'compilation-error)))))))
|
|
||||||
|
|
||||||
(provide 'haskell-commands)
|
|
Binary file not shown.
@@ -1,64 +0,0 @@
|
|||||||
;;; haskell-compat.el --- legacy/compatibility backports for haskell-mode
|
|
||||||
;;
|
|
||||||
;; Filename: haskell-compat.el
|
|
||||||
;; Description: legacy/compatibility backports for haskell-mode
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
(require 'etags)
|
|
||||||
(require 'ring)
|
|
||||||
(require 'outline)
|
|
||||||
(require 'xref nil t)
|
|
||||||
|
|
||||||
(eval-when-compile
|
|
||||||
(setq byte-compile-warnings '(not cl-functions obsolete)))
|
|
||||||
|
|
||||||
;; Missing in Emacs23, stolen from Emacs24's `subr.el'
|
|
||||||
(unless (fboundp 'process-live-p)
|
|
||||||
(defun process-live-p (process)
|
|
||||||
"Returns non-nil if PROCESS is alive.
|
|
||||||
A process is considered alive if its status is `run', `open',
|
|
||||||
`listen', `connect' or `stop'."
|
|
||||||
(memq (process-status process)
|
|
||||||
'(run open listen connect stop))))
|
|
||||||
|
|
||||||
;; Cross-referencing commands have been replaced since Emacs 25.1.
|
|
||||||
;; These aliases are required to provide backward compatibility.
|
|
||||||
(unless (fboundp 'xref-push-marker-stack)
|
|
||||||
(defalias 'xref-pop-marker-stack 'pop-tag-mark)
|
|
||||||
|
|
||||||
(defun xref-push-marker-stack ()
|
|
||||||
"Add point to the marker stack."
|
|
||||||
(ring-insert find-tag-marker-ring (point-marker))))
|
|
||||||
|
|
||||||
(unless (fboundp 'outline-hide-sublevels)
|
|
||||||
(defalias 'outline-hide-sublevels 'hide-sublevels))
|
|
||||||
|
|
||||||
(unless (fboundp 'outline-show-subtree)
|
|
||||||
(defalias 'outline-show-subtree 'show-subtree))
|
|
||||||
|
|
||||||
(unless (fboundp 'outline-hide-sublevels)
|
|
||||||
(defalias 'outline-hide-sublevels 'hide-sublevels))
|
|
||||||
|
|
||||||
(unless (fboundp 'outline-show-subtree)
|
|
||||||
(defalias 'outline-show-subtree 'show-subtree))
|
|
||||||
|
|
||||||
(provide 'haskell-compat)
|
|
||||||
|
|
||||||
;;; haskell-compat.el ends here
|
|
Binary file not shown.
@@ -1,158 +0,0 @@
|
|||||||
;;; haskell-compile.el --- Haskell/GHC compilation sub-mode
|
|
||||||
|
|
||||||
;; Copyright (C) 2013 Herbert Valerio Riedel
|
|
||||||
|
|
||||||
;; Author: Herbert Valerio Riedel <hvr@gnu.org>
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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 file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Simple GHC-centric compilation sub-mode; see info node
|
|
||||||
;; `(haskell-mode)compilation' for more information
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'compile)
|
|
||||||
(require 'haskell-cabal)
|
|
||||||
|
|
||||||
(defgroup haskell-compile nil
|
|
||||||
"Settings for Haskell compilation mode"
|
|
||||||
:link '(custom-manual "(haskell-mode)compilation")
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defcustom haskell-compile-cabal-build-command
|
|
||||||
"cd %s && cabal build --ghc-option=-ferror-spans"
|
|
||||||
"Default build command to use for `haskell-cabal-build' when a cabal file is detected.
|
|
||||||
The `%s' placeholder is replaced by the cabal package top folder."
|
|
||||||
:group 'haskell-compile
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom haskell-compile-cabal-build-alt-command
|
|
||||||
"cd %s && cabal clean -s && cabal build --ghc-option=-ferror-spans"
|
|
||||||
"Alternative build command to use when `haskell-cabal-build' is called with a negative prefix argument.
|
|
||||||
The `%s' placeholder is replaced by the cabal package top folder."
|
|
||||||
:group 'haskell-compile
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom haskell-compile-command
|
|
||||||
"ghc -Wall -ferror-spans -fforce-recomp -c %s"
|
|
||||||
"Default build command to use for `haskell-cabal-build' when no cabal file is detected.
|
|
||||||
The `%s' placeholder is replaced by the current buffer's filename."
|
|
||||||
:group 'haskell-compile
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom haskell-compile-ghc-filter-linker-messages
|
|
||||||
t
|
|
||||||
"Filter out unremarkable \"Loading package...\" linker messages during compilation."
|
|
||||||
:group 'haskell-compile
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defconst haskell-compilation-error-regexp-alist
|
|
||||||
`((,(concat
|
|
||||||
"^\\(?1:[^ \t\r\n]+?\\):"
|
|
||||||
"\\(?:"
|
|
||||||
"\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?" ;; "121:1" & "12:3-5"
|
|
||||||
"\\|"
|
|
||||||
"(\\(?2:[0-9]+\\),\\(?4:[0-9]+\\))-(\\(?3:[0-9]+\\),\\(?5:[0-9]+\\))" ;; "(289,5)-(291,36)"
|
|
||||||
"\\)"
|
|
||||||
":\\(?6: Warning:\\)?")
|
|
||||||
1 (2 . 3) (4 . 5) (6 . nil)) ;; error/warning locus
|
|
||||||
|
|
||||||
;; multiple declarations
|
|
||||||
("^ \\(?:Declared at:\\| \\) \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)$"
|
|
||||||
1 2 4 0) ;; info locus
|
|
||||||
|
|
||||||
;; this is the weakest pattern as it's subject to line wrapping et al.
|
|
||||||
(" at \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?[)]?$"
|
|
||||||
1 2 (4 . 5) 0)) ;; info locus
|
|
||||||
"Regexps used for matching GHC compile messages.
|
|
||||||
See `compilation-error-regexp-alist' for semantics.")
|
|
||||||
|
|
||||||
(defvar haskell-compilation-mode-map
|
|
||||||
(let ((map (make-sparse-keymap)))
|
|
||||||
(set-keymap-parent map compilation-mode-map))
|
|
||||||
"Keymap for `haskell-compilation-mode' buffers.
|
|
||||||
This is a child of `compilation-mode-map'.")
|
|
||||||
|
|
||||||
(defun haskell-compilation-filter-hook ()
|
|
||||||
"Local `compilation-filter-hook' for `haskell-compilation-mode'."
|
|
||||||
|
|
||||||
(when haskell-compile-ghc-filter-linker-messages
|
|
||||||
(delete-matching-lines "^Loading package [^ \t\r\n]+ [.]+ linking [.]+ done\\.$"
|
|
||||||
(if (boundp 'compilation-filter-start) ;; available since Emacs 24.2
|
|
||||||
(save-excursion (goto-char compilation-filter-start)
|
|
||||||
(line-beginning-position))
|
|
||||||
(point-min))
|
|
||||||
(point))))
|
|
||||||
|
|
||||||
(define-compilation-mode haskell-compilation-mode "HsCompilation"
|
|
||||||
"Haskell/GHC specific `compilation-mode' derivative.
|
|
||||||
This mode provides support for GHC 7.[46]'s compile
|
|
||||||
messages. Specifically, also the `-ferror-spans` source location
|
|
||||||
format is supported, as well as info-locations within compile
|
|
||||||
messages pointing to additional source locations.
|
|
||||||
|
|
||||||
See Info node `(haskell-mode)compilation' for more details."
|
|
||||||
(set (make-local-variable 'compilation-error-regexp-alist)
|
|
||||||
haskell-compilation-error-regexp-alist)
|
|
||||||
|
|
||||||
(add-hook 'compilation-filter-hook
|
|
||||||
'haskell-compilation-filter-hook nil t)
|
|
||||||
)
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-compile (&optional edit-command)
|
|
||||||
"Compile the Haskell program including the current buffer.
|
|
||||||
Tries to locate the next cabal description in current or parent
|
|
||||||
folders via `haskell-cabal-find-dir' and if found, invoke
|
|
||||||
`haskell-compile-cabal-build-command' from the cabal package root
|
|
||||||
folder. If no cabal package could be detected,
|
|
||||||
`haskell-compile-command' is used instead.
|
|
||||||
|
|
||||||
If prefix argument EDIT-COMMAND is non-nil (and not a negative
|
|
||||||
prefix `-'), `haskell-compile' prompts for custom compile
|
|
||||||
command.
|
|
||||||
|
|
||||||
If EDIT-COMMAND contains the negative prefix argument `-',
|
|
||||||
`haskell-compile' calls the alternative command defined in
|
|
||||||
`haskell-compile-cabal-build-alt-command' if a cabal package was
|
|
||||||
detected.
|
|
||||||
|
|
||||||
`haskell-compile' uses `haskell-compilation-mode' which is
|
|
||||||
derived from `compilation-mode'. See Info
|
|
||||||
node `(haskell-mode)compilation' for more details."
|
|
||||||
(interactive "P")
|
|
||||||
(save-some-buffers (not compilation-ask-about-save)
|
|
||||||
(if (boundp 'compilation-save-buffers-predicate) ;; since Emacs 24.1(?)
|
|
||||||
compilation-save-buffers-predicate))
|
|
||||||
(let* ((cabdir (haskell-cabal-find-dir))
|
|
||||||
(command1 (if (eq edit-command '-)
|
|
||||||
haskell-compile-cabal-build-alt-command
|
|
||||||
haskell-compile-cabal-build-command))
|
|
||||||
(srcname (buffer-file-name))
|
|
||||||
(command (if cabdir
|
|
||||||
(format command1 cabdir)
|
|
||||||
(if (and srcname (derived-mode-p 'haskell-mode))
|
|
||||||
(format haskell-compile-command srcname)
|
|
||||||
command1))))
|
|
||||||
(when (and edit-command (not (eq edit-command '-)))
|
|
||||||
(setq command (compilation-read-command command)))
|
|
||||||
|
|
||||||
(compilation-start command 'haskell-compilation-mode)))
|
|
||||||
|
|
||||||
(provide 'haskell-compile)
|
|
||||||
;;; haskell-compile.el ends here
|
|
Binary file not shown.
@@ -1,132 +0,0 @@
|
|||||||
;;; haskell-complete-module.el --- A fast way to complete Haskell module names
|
|
||||||
|
|
||||||
;; Copyright (c) 2014 Chris Done. All rights reserved.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
|
|
||||||
(defcustom haskell-complete-module-preferred
|
|
||||||
'()
|
|
||||||
"Override ordering of module results by specifying preferred modules."
|
|
||||||
:group 'haskell
|
|
||||||
:type '(repeat string))
|
|
||||||
|
|
||||||
(defcustom haskell-complete-module-max-display
|
|
||||||
10
|
|
||||||
"Maximum items to display in minibuffer."
|
|
||||||
:group 'haskell
|
|
||||||
:type 'number)
|
|
||||||
|
|
||||||
(defun haskell-complete-module-read (prompt candidates)
|
|
||||||
"Interactively auto-complete from a list of candidates."
|
|
||||||
(let ((continue t)
|
|
||||||
(stack (list))
|
|
||||||
(pattern "")
|
|
||||||
(result nil))
|
|
||||||
(delete-dups candidates)
|
|
||||||
(setq candidates
|
|
||||||
(sort candidates
|
|
||||||
(lambda (a b)
|
|
||||||
(let ((a-mem (member a haskell-complete-module-preferred))
|
|
||||||
(b-mem (member b haskell-complete-module-preferred)))
|
|
||||||
(cond
|
|
||||||
((and a-mem (not b-mem))
|
|
||||||
t)
|
|
||||||
((and b-mem (not a-mem))
|
|
||||||
nil)
|
|
||||||
(t
|
|
||||||
(string< a b)))))))
|
|
||||||
(while (not result)
|
|
||||||
(let ((key
|
|
||||||
(key-description
|
|
||||||
(vector
|
|
||||||
(read-key
|
|
||||||
(concat (propertize prompt 'face 'minibuffer-prompt)
|
|
||||||
(propertize pattern 'face 'font-lock-type-face)
|
|
||||||
"{"
|
|
||||||
(mapconcat #'identity
|
|
||||||
(let* ((i 0))
|
|
||||||
(cl-loop for candidate in candidates
|
|
||||||
while (<= i haskell-complete-module-max-display)
|
|
||||||
do (cl-incf i)
|
|
||||||
collect (cond ((> i haskell-complete-module-max-display)
|
|
||||||
"...")
|
|
||||||
((= i 1)
|
|
||||||
(propertize candidate 'face 'ido-first-match-face))
|
|
||||||
(t candidate))))
|
|
||||||
" | ")
|
|
||||||
"}"))))))
|
|
||||||
(cond
|
|
||||||
((string= key "C-g")
|
|
||||||
(keyboard-quit))
|
|
||||||
((string= key "DEL")
|
|
||||||
(unless (null stack)
|
|
||||||
(setq candidates (pop stack)))
|
|
||||||
(unless (string= "" pattern)
|
|
||||||
(setq pattern (substring pattern 0 -1))))
|
|
||||||
((string= key "RET")
|
|
||||||
(setq result (or (car candidates)
|
|
||||||
pattern)))
|
|
||||||
((string= key "<left>")
|
|
||||||
(setq candidates
|
|
||||||
(append (last candidates)
|
|
||||||
(butlast candidates))))
|
|
||||||
((string= key "<right>")
|
|
||||||
(setq candidates
|
|
||||||
(append (cdr candidates)
|
|
||||||
(list (car candidates)))))
|
|
||||||
(t
|
|
||||||
(when (string-match "[A-Za-z0-9_'.]+" key)
|
|
||||||
(push candidates stack)
|
|
||||||
(setq pattern (concat pattern key))
|
|
||||||
(setq candidates (haskell-complete-module pattern candidates)))))))
|
|
||||||
result))
|
|
||||||
|
|
||||||
(defun haskell-complete-module (pattern candidates)
|
|
||||||
"Filter the CANDIDATES using PATTERN."
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(cl-loop for candidate in candidates
|
|
||||||
when (haskell-complete-module-match pattern candidate)
|
|
||||||
collect candidate)))
|
|
||||||
|
|
||||||
(defun haskell-complete-module-match (pattern text)
|
|
||||||
"Match PATTERN against TEXT."
|
|
||||||
(string-match (haskell-complete-module-regexp pattern)
|
|
||||||
text))
|
|
||||||
|
|
||||||
(defun haskell-complete-module-regexp (pattern)
|
|
||||||
"Make a regular expression for the given module pattern. Example:
|
|
||||||
|
|
||||||
\"c.m.s\" -> \"^c[^.]*\\.m[^.]*\\.s[^.]*\"
|
|
||||||
|
|
||||||
"
|
|
||||||
(let ((components (mapcar #'haskell-complete-module-component
|
|
||||||
(split-string pattern "\\." t))))
|
|
||||||
(concat "^"
|
|
||||||
(mapconcat #'identity
|
|
||||||
components
|
|
||||||
"\\."))))
|
|
||||||
|
|
||||||
(defun haskell-complete-module-component (component)
|
|
||||||
"Make a regular expression for the given component. Example:
|
|
||||||
|
|
||||||
\"co\" -> \"c[^.]*o[^.]*\"
|
|
||||||
|
|
||||||
"
|
|
||||||
(replace-regexp-in-string "\\(.\\)" "\\1[^.]*" component))
|
|
||||||
|
|
||||||
(provide 'haskell-complete-module)
|
|
Binary file not shown.
@@ -1,362 +0,0 @@
|
|||||||
;;; haskell-customize.el --- Customization settings
|
|
||||||
|
|
||||||
;; Copyright (c) 2014 Chris Done. All rights reserved.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Customization variables
|
|
||||||
|
|
||||||
(defgroup haskell nil
|
|
||||||
"Major mode for editing Haskell programs."
|
|
||||||
:link '(custom-manual "(haskell-mode)")
|
|
||||||
:group 'languages
|
|
||||||
:prefix "haskell-")
|
|
||||||
|
|
||||||
(defvar haskell-mode-pkg-base-dir (file-name-directory load-file-name)
|
|
||||||
"Package base directory of installed `haskell-mode'.
|
|
||||||
Used for locating additional package data files.")
|
|
||||||
|
|
||||||
(defcustom haskell-completing-read-function 'ido-completing-read
|
|
||||||
"Default function to use for completion."
|
|
||||||
:group 'haskell
|
|
||||||
:type '(choice
|
|
||||||
(function-item :tag "ido" :value ido-completing-read)
|
|
||||||
(function-item :tag "helm" :value helm--completing-read-default)
|
|
||||||
(function-item :tag "completing-read" :value completing-read)
|
|
||||||
(function :tag "Custom function")))
|
|
||||||
|
|
||||||
(defcustom haskell-process-type
|
|
||||||
'auto
|
|
||||||
"The inferior Haskell process type to use."
|
|
||||||
:type '(choice (const auto) (const ghci) (const cabal-repl) (const cabal-dev) (const cabal-ghci))
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-wrapper-function
|
|
||||||
#'identity
|
|
||||||
"Wrap or transform haskell process commands using this function.
|
|
||||||
|
|
||||||
Can be set to a custom function which takes a list of arguments
|
|
||||||
and returns a possibly-modified list.
|
|
||||||
|
|
||||||
The following example function arranges for all haskell process
|
|
||||||
commands to be started in the current nix-shell environment:
|
|
||||||
|
|
||||||
(lambda (argv) (append (list \"nix-shell\" \"-I\" \".\" \"--command\" )
|
|
||||||
(list (mapconcat 'identity argv \" \"))))
|
|
||||||
|
|
||||||
See Info Node `(emacs)Directory Variables' for a way to set this option on
|
|
||||||
a per-project basis."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type '(choice
|
|
||||||
(function-item :tag "None" :value identity)
|
|
||||||
(function :tag "Custom function")))
|
|
||||||
|
|
||||||
(defcustom haskell-ask-also-kill-buffers
|
|
||||||
t
|
|
||||||
"Ask whether to kill all associated buffers when a session
|
|
||||||
process is killed."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Configuration
|
|
||||||
|
|
||||||
(defvar haskell-process-end-hook nil
|
|
||||||
"Hook for when the haskell process ends.")
|
|
||||||
|
|
||||||
(defgroup haskell-interactive nil
|
|
||||||
"Settings for REPL interaction via `haskell-interactive-mode'"
|
|
||||||
:link '(custom-manual "(haskell-mode)haskell-interactive-mode")
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defcustom haskell-process-path-ghci
|
|
||||||
"ghci"
|
|
||||||
"The path for starting ghci."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type '(choice string (repeat string)))
|
|
||||||
|
|
||||||
(defcustom haskell-process-path-cabal
|
|
||||||
"cabal"
|
|
||||||
"Path to the `cabal' executable."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type '(choice string (repeat string)))
|
|
||||||
|
|
||||||
(defcustom haskell-process-path-cabal-ghci
|
|
||||||
"cabal-ghci"
|
|
||||||
"The path for starting cabal-ghci."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type '(choice string (repeat string)))
|
|
||||||
|
|
||||||
(defcustom haskell-process-path-cabal-dev
|
|
||||||
"cabal-dev"
|
|
||||||
"The path for starting cabal-dev."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type '(choice string (repeat string)))
|
|
||||||
|
|
||||||
(defcustom haskell-process-args-ghci
|
|
||||||
'("-ferror-spans")
|
|
||||||
"Any arguments for starting ghci."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type '(repeat (string :tag "Argument")))
|
|
||||||
|
|
||||||
(defcustom haskell-process-args-cabal-repl
|
|
||||||
'("--ghc-option=-ferror-spans")
|
|
||||||
"Additional arguments to for `cabal repl' invocation.
|
|
||||||
Note: The settings in `haskell-process-path-ghci' and
|
|
||||||
`haskell-process-args-ghci' are not automatically reused as `cabal repl'
|
|
||||||
currently invokes `ghc --interactive'. Use
|
|
||||||
`--with-ghc=<path-to-executable>' if you want to use a different
|
|
||||||
interactive GHC frontend; use `--ghc-option=<ghc-argument>' to
|
|
||||||
pass additional flags to `ghc'."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type '(repeat (string :tag "Argument")))
|
|
||||||
|
|
||||||
(defcustom haskell-process-do-cabal-format-string
|
|
||||||
":!cd %s && %s"
|
|
||||||
"The way to run cabal comands. It takes two arguments -- the directory and the command.
|
|
||||||
See `haskell-process-do-cabal' for more details."
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
(defcustom haskell-process-log
|
|
||||||
nil
|
|
||||||
"Enable debug logging to \"*haskell-process-log*\" buffer."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-show-debug-tips
|
|
||||||
t
|
|
||||||
"Show debugging tips when starting the process."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-notify-p
|
|
||||||
nil
|
|
||||||
"Notify using notifications.el (if loaded)?"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-no-warn-orphans
|
|
||||||
t
|
|
||||||
"Suggest adding -fno-warn-orphans pragma to file when getting orphan warnings."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-hoogle-imports
|
|
||||||
nil
|
|
||||||
"Suggest to add import statements using Hoogle as a backend."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-hayoo-imports
|
|
||||||
nil
|
|
||||||
"Suggest to add import statements using Hayoo as a backend."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-hayoo-query-url
|
|
||||||
"http://hayoo.fh-wedel.de/json/?query=%s"
|
|
||||||
"Query url for json hayoo results."
|
|
||||||
:type 'string
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-haskell-docs-imports
|
|
||||||
nil
|
|
||||||
"Suggest to add import statements using haskell-docs as a backend."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-add-package
|
|
||||||
t
|
|
||||||
"Suggest to add packages to your .cabal file when Cabal says it
|
|
||||||
is a member of the hidden package, blah blah."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-language-pragmas
|
|
||||||
t
|
|
||||||
"Suggest adding LANGUAGE pragmas recommended by GHC."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-remove-import-lines
|
|
||||||
nil
|
|
||||||
"Suggest removing import lines as warned by GHC."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-overloaded-strings
|
|
||||||
t
|
|
||||||
"Suggest adding OverloadedStrings pragma to file when getting type mismatches with [Char]."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-check-cabal-config-on-load
|
|
||||||
t
|
|
||||||
"Check changes cabal config on loading Haskell files and
|
|
||||||
restart the GHCi process if changed.."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-prompt-restart-on-cabal-change
|
|
||||||
t
|
|
||||||
"Ask whether to restart the GHCi process when the Cabal file
|
|
||||||
has changed?"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-auto-import-loaded-modules
|
|
||||||
nil
|
|
||||||
"Auto import the modules reported by GHC to have been loaded?"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-reload-with-fbytecode
|
|
||||||
nil
|
|
||||||
"When using -fobject-code, auto reload with -fbyte-code (and
|
|
||||||
then restore the -fobject-code) so that all module info and
|
|
||||||
imports become available?"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-use-presentation-mode
|
|
||||||
nil
|
|
||||||
"Use presentation mode to show things like type info instead of
|
|
||||||
printing to the message area."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-process-suggest-restart
|
|
||||||
t
|
|
||||||
"Suggest restarting the process when it has died"
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-mode-scroll-to-bottom
|
|
||||||
nil
|
|
||||||
"Scroll to bottom in the REPL always."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-popup-errors
|
|
||||||
t
|
|
||||||
"Popup errors in a separate buffer."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-mode-collapse
|
|
||||||
nil
|
|
||||||
"Collapse printed results."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-types-for-show-ambiguous
|
|
||||||
t
|
|
||||||
"Show types when there's no Show instance or there's an
|
|
||||||
ambiguous class constraint."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-mode-eval-pretty
|
|
||||||
nil
|
|
||||||
"Print eval results that can be parsed as Show instances prettily. Requires sexp-show (on Hackage)."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defvar haskell-interactive-prompt "λ> "
|
|
||||||
"The prompt to use.")
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-mode-eval-mode
|
|
||||||
nil
|
|
||||||
"Use the given mode's font-locking to render some text."
|
|
||||||
:type '(choice function (const :tag "None" nil))
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-mode-hide-multi-line-errors
|
|
||||||
nil
|
|
||||||
"Hide collapsible multi-line compile messages by default."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-mode-delete-superseded-errors
|
|
||||||
t
|
|
||||||
"Whether to delete compile messages superseded by recompile/reloads."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-interactive-mode-include-file-name
|
|
||||||
t
|
|
||||||
"Include the file name of the module being compiled when
|
|
||||||
printing compilation messages."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-import-mapping
|
|
||||||
'()
|
|
||||||
"Support a mapping from module to import lines.
|
|
||||||
|
|
||||||
E.g. '((\"Data.Map\" . \"import qualified Data.Map as M
|
|
||||||
import Data.Map (Map)
|
|
||||||
\"))
|
|
||||||
|
|
||||||
This will import
|
|
||||||
|
|
||||||
import qualified Data.Map as M
|
|
||||||
import Data.Map (Map)
|
|
||||||
|
|
||||||
when Data.Map is the candidate.
|
|
||||||
|
|
||||||
"
|
|
||||||
:type '(repeat (cons (string :tag "Module name")
|
|
||||||
(string :tag "Import lines")))
|
|
||||||
:group 'haskell-interactive)
|
|
||||||
|
|
||||||
(defcustom haskell-language-extensions
|
|
||||||
'()
|
|
||||||
"Language extensions in use. Should be in format: -XFoo, -XNoFoo etc."
|
|
||||||
:group 'shm
|
|
||||||
:type '(repeat 'string))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Accessor functions
|
|
||||||
|
|
||||||
(defun haskell-process-type ()
|
|
||||||
"Return `haskell-process-type', or a guess if that variable is 'auto."
|
|
||||||
(if (eq 'auto haskell-process-type)
|
|
||||||
(if (locate-dominating-file
|
|
||||||
default-directory
|
|
||||||
(lambda (d)
|
|
||||||
(or (file-directory-p (expand-file-name ".cabal-sandbox" d))
|
|
||||||
(cl-find-if (lambda (f) (string-match-p ".\\.cabal\\'" f)) (directory-files d)))))
|
|
||||||
'cabal-repl
|
|
||||||
'ghci)
|
|
||||||
haskell-process-type))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-customize ()
|
|
||||||
"Browse the haskell customize sub-tree.
|
|
||||||
This calls 'customize-browse' with haskell as argument and makes
|
|
||||||
sure all haskell customize definitions have been loaded."
|
|
||||||
(interactive)
|
|
||||||
;; make sure all modules with (defcustom ...)s are loaded
|
|
||||||
(mapc 'require
|
|
||||||
'(haskell-checkers haskell-compile haskell-doc haskell-font-lock haskell-indentation haskell-indent haskell-interactive-mode haskell-menu haskell-process haskell-yas inf-haskell))
|
|
||||||
(customize-browse 'haskell))
|
|
||||||
|
|
||||||
(provide 'haskell-customize)
|
|
Binary file not shown.
@@ -1,738 +0,0 @@
|
|||||||
;;; haskell-debug.el --- Debugging mode via GHCi
|
|
||||||
|
|
||||||
;; Copyright (c) 2014 Chris Done. All rights reserved.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'haskell-session)
|
|
||||||
(require 'haskell-process)
|
|
||||||
(require 'haskell-interactive-mode)
|
|
||||||
(require 'haskell-font-lock)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Configuration
|
|
||||||
|
|
||||||
(defgroup haskell-debug nil
|
|
||||||
"Settings for debugging support."
|
|
||||||
:link '(custom-manual "(haskell-mode)haskell-debug")
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defface haskell-debug-warning-face
|
|
||||||
'((t :inherit 'compilation-warning))
|
|
||||||
"Face for warnings."
|
|
||||||
:group 'haskell-debug)
|
|
||||||
|
|
||||||
(defface haskell-debug-trace-number-face
|
|
||||||
'((t :weight bold :background "#f5f5f5"))
|
|
||||||
"Face for numbers in backtrace."
|
|
||||||
:group 'haskell-debug)
|
|
||||||
|
|
||||||
(defface haskell-debug-newline-face
|
|
||||||
'((t :weight bold :background "#f0f0f0"))
|
|
||||||
"Face for newlines in trace steps."
|
|
||||||
:group 'haskell-debug)
|
|
||||||
|
|
||||||
(defface haskell-debug-keybinding-face
|
|
||||||
'((t :inherit 'font-lock-type-face :weight bold))
|
|
||||||
"Face for keybindings."
|
|
||||||
:group 'haskell-debug)
|
|
||||||
|
|
||||||
(defface haskell-debug-heading-face
|
|
||||||
'((t :inherit 'font-lock-keyword-face))
|
|
||||||
"Face for headings."
|
|
||||||
:group 'haskell-debug)
|
|
||||||
|
|
||||||
(defface haskell-debug-muted-face
|
|
||||||
'((t :foreground "#999"))
|
|
||||||
"Face for muteds."
|
|
||||||
:group 'haskell-debug)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Mode
|
|
||||||
|
|
||||||
(define-derived-mode haskell-debug-mode
|
|
||||||
text-mode "Debug"
|
|
||||||
"Major mode for debugging Haskell via GHCi.")
|
|
||||||
|
|
||||||
(define-key haskell-debug-mode-map (kbd "g") 'haskell-debug/refresh)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "s") 'haskell-debug/step)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "t") 'haskell-debug/trace)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "d") 'haskell-debug/delete)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "b") 'haskell-debug/break-on-function)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "a") 'haskell-debug/abandon)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "c") 'haskell-debug/continue)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "p") 'haskell-debug/previous)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "n") 'haskell-debug/next)
|
|
||||||
(define-key haskell-debug-mode-map (kbd "RET") 'haskell-debug/select)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Globals
|
|
||||||
|
|
||||||
(defvar haskell-debug-history-cache nil
|
|
||||||
"Cache of the tracing history.")
|
|
||||||
|
|
||||||
(defvar haskell-debug-bindings-cache nil
|
|
||||||
"Cache of the current step's bindings.")
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Macros
|
|
||||||
|
|
||||||
(defmacro haskell-debug-with-breakpoints (&rest body)
|
|
||||||
"Breakpoints need to exist to start stepping."
|
|
||||||
`(if (haskell-debug-get-breakpoints)
|
|
||||||
,@body
|
|
||||||
(error "No breakpoints to step into!")))
|
|
||||||
|
|
||||||
(defmacro haskell-debug-with-modules (&rest body)
|
|
||||||
"Modules need to exist to do debugging stuff."
|
|
||||||
`(if (haskell-debug-get-modules)
|
|
||||||
,@body
|
|
||||||
(error "No modules loaded!")))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Interactive functions
|
|
||||||
|
|
||||||
(defun haskell-debug/select ()
|
|
||||||
"Select whatever is at point."
|
|
||||||
(interactive)
|
|
||||||
(cond
|
|
||||||
((get-text-property (point) 'break)
|
|
||||||
(let ((break (get-text-property (point) 'break)))
|
|
||||||
(haskell-debug-highlight (plist-get break :path)
|
|
||||||
(plist-get break :span))))
|
|
||||||
((get-text-property (point) 'module)
|
|
||||||
(let ((break (get-text-property (point) 'module)))
|
|
||||||
(haskell-debug-highlight (plist-get break :path))))))
|
|
||||||
|
|
||||||
(defun haskell-debug/abandon ()
|
|
||||||
"Abandon the current computation."
|
|
||||||
(interactive)
|
|
||||||
(haskell-debug-with-breakpoints
|
|
||||||
(haskell-process-queue-sync-request (haskell-debug-process) ":abandon")
|
|
||||||
(message "Computation abandoned.")
|
|
||||||
(setq haskell-debug-history-cache nil)
|
|
||||||
(setq haskell-debug-bindings-cache nil)
|
|
||||||
(haskell-debug/refresh)))
|
|
||||||
|
|
||||||
(defun haskell-debug/continue ()
|
|
||||||
"Continue the current computation."
|
|
||||||
(interactive)
|
|
||||||
(haskell-debug-with-breakpoints
|
|
||||||
(haskell-process-queue-sync-request (haskell-debug-process) ":continue")
|
|
||||||
(message "Computation continued.")
|
|
||||||
(setq haskell-debug-history-cache nil)
|
|
||||||
(setq haskell-debug-bindings-cache nil)
|
|
||||||
(haskell-debug/refresh)))
|
|
||||||
|
|
||||||
(defun haskell-debug/break-on-function ()
|
|
||||||
"Break on function IDENT."
|
|
||||||
(interactive)
|
|
||||||
(haskell-debug-with-modules
|
|
||||||
(let ((ident (read-from-minibuffer "Function: "
|
|
||||||
(haskell-ident-at-point))))
|
|
||||||
(haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
(concat ":break "
|
|
||||||
ident))
|
|
||||||
(message "Breaking on function: %s" ident)
|
|
||||||
(haskell-debug/refresh))))
|
|
||||||
|
|
||||||
(defun haskell-debug/start-step (expr)
|
|
||||||
"Start stepping EXPR."
|
|
||||||
(interactive (list (read-from-minibuffer "Expression to step through: ")))
|
|
||||||
(haskell-debug/step expr))
|
|
||||||
|
|
||||||
(defun haskell-debug/breakpoint-numbers ()
|
|
||||||
"List breakpoint numbers."
|
|
||||||
(interactive)
|
|
||||||
(let ((breakpoints (mapcar (lambda (breakpoint)
|
|
||||||
(number-to-string (plist-get breakpoint :number)))
|
|
||||||
(haskell-debug-get-breakpoints))))
|
|
||||||
(if (null breakpoints)
|
|
||||||
(message "No breakpoints.")
|
|
||||||
(message "Breakpoint(s): %s"
|
|
||||||
(mapconcat #'identity
|
|
||||||
breakpoints
|
|
||||||
", ")))))
|
|
||||||
|
|
||||||
(defun haskell-debug/next ()
|
|
||||||
"Go to next step to inspect bindings."
|
|
||||||
(interactive)
|
|
||||||
(haskell-debug-with-breakpoints
|
|
||||||
(haskell-debug-navigate "forward")))
|
|
||||||
|
|
||||||
(defun haskell-debug/previous ()
|
|
||||||
"Go to previous step to inspect the bindings."
|
|
||||||
(interactive)
|
|
||||||
(haskell-debug-with-breakpoints
|
|
||||||
(haskell-debug-navigate "back")))
|
|
||||||
|
|
||||||
(defun haskell-debug/refresh ()
|
|
||||||
"Refresh the debugger buffer."
|
|
||||||
(interactive)
|
|
||||||
(with-current-buffer (haskell-debug-buffer-name (haskell-debug-session))
|
|
||||||
(cd (haskell-session-current-dir (haskell-debug-session)))
|
|
||||||
(let ((inhibit-read-only t)
|
|
||||||
(p (point)))
|
|
||||||
(erase-buffer)
|
|
||||||
(insert (propertize (concat "Debugging "
|
|
||||||
(haskell-session-name (haskell-debug-session))
|
|
||||||
"\n\n")
|
|
||||||
'face `((:weight bold))))
|
|
||||||
(let ((modules (haskell-debug-get-modules))
|
|
||||||
(breakpoints (haskell-debug-get-breakpoints))
|
|
||||||
(context (haskell-debug-get-context))
|
|
||||||
(history (haskell-debug-get-history)))
|
|
||||||
(unless modules
|
|
||||||
(insert (propertize "You have to load a module to start debugging."
|
|
||||||
'face
|
|
||||||
'haskell-debug-warning-face)
|
|
||||||
"\n\n"))
|
|
||||||
(haskell-debug-insert-bindings modules breakpoints context)
|
|
||||||
(when modules
|
|
||||||
(haskell-debug-insert-current-context context history)
|
|
||||||
(haskell-debug-insert-breakpoints breakpoints))
|
|
||||||
(haskell-debug-insert-modules modules))
|
|
||||||
(insert "\n")
|
|
||||||
(goto-char (min (point-max) p)))))
|
|
||||||
|
|
||||||
(defun haskell-debug/delete ()
|
|
||||||
"Delete whatever's at the point."
|
|
||||||
(interactive)
|
|
||||||
(cond
|
|
||||||
((get-text-property (point) 'break)
|
|
||||||
(let ((break (get-text-property (point) 'break)))
|
|
||||||
(when (y-or-n-p (format "Delete breakpoint #%d?"
|
|
||||||
(plist-get break :number)))
|
|
||||||
(haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
(format ":delete %d"
|
|
||||||
(plist-get break :number)))
|
|
||||||
(haskell-debug/refresh))))))
|
|
||||||
|
|
||||||
(defun haskell-debug/trace ()
|
|
||||||
"Trace the expression."
|
|
||||||
(interactive)
|
|
||||||
(haskell-debug-with-modules
|
|
||||||
(haskell-debug-with-breakpoints
|
|
||||||
(let ((expr (read-from-minibuffer "Expression to trace: "
|
|
||||||
(haskell-ident-at-point))))
|
|
||||||
(haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
(concat ":trace " expr))
|
|
||||||
(message "Tracing expression: %s" expr)
|
|
||||||
(haskell-debug/refresh)))))
|
|
||||||
|
|
||||||
(defun haskell-debug/step (&optional expr)
|
|
||||||
"Step into the next function."
|
|
||||||
(interactive)
|
|
||||||
(haskell-debug-with-breakpoints
|
|
||||||
(let* ((breakpoints (haskell-debug-get-breakpoints))
|
|
||||||
(context (haskell-debug-get-context))
|
|
||||||
(string
|
|
||||||
(haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
(if expr
|
|
||||||
(concat ":step " expr)
|
|
||||||
":step"))))
|
|
||||||
(cond
|
|
||||||
((string= string "not stopped at a breakpoint\n")
|
|
||||||
(if haskell-debug-bindings-cache
|
|
||||||
(progn (setq haskell-debug-bindings-cache nil)
|
|
||||||
(haskell-debug/refresh))
|
|
||||||
(call-interactively 'haskell-debug/start-step)))
|
|
||||||
(t (let ((maybe-stopped-at (haskell-debug-parse-stopped-at string)))
|
|
||||||
(cond
|
|
||||||
(maybe-stopped-at
|
|
||||||
(setq haskell-debug-bindings-cache
|
|
||||||
maybe-stopped-at)
|
|
||||||
(message "Computation paused.")
|
|
||||||
(haskell-debug/refresh))
|
|
||||||
(t
|
|
||||||
(if context
|
|
||||||
(message "Computation finished.")
|
|
||||||
(when (y-or-n-p "Computation completed without breaking. Reload the module and retry?")
|
|
||||||
(message "Reloading and resetting breakpoints...")
|
|
||||||
(haskell-interactive-mode-reset-error (haskell-debug-session))
|
|
||||||
(cl-loop for break in breakpoints
|
|
||||||
do (haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
(concat ":load " (plist-get break :path))))
|
|
||||||
(cl-loop for break in breakpoints
|
|
||||||
do (haskell-debug-break break))
|
|
||||||
(haskell-debug/step expr)))))))))
|
|
||||||
(haskell-debug/refresh)))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Internal functions
|
|
||||||
|
|
||||||
(defun haskell-debug-session ()
|
|
||||||
"Get the Haskell session."
|
|
||||||
(or (haskell-session-maybe)
|
|
||||||
(error "No Haskell session associated with this debug
|
|
||||||
buffer. Please just close the buffer and start again.")))
|
|
||||||
|
|
||||||
(defun haskell-debug-process ()
|
|
||||||
"Get the Haskell session."
|
|
||||||
(or (haskell-session-process (haskell-session-maybe))
|
|
||||||
(error "No Haskell session associated with this debug
|
|
||||||
buffer. Please just close the buffer and start again.")))
|
|
||||||
|
|
||||||
(defun haskell-debug-buffer-name (session)
|
|
||||||
"The debug buffer name for the current session."
|
|
||||||
(format "*debug:%s*"
|
|
||||||
(haskell-session-name session)))
|
|
||||||
|
|
||||||
(defun haskell-debug-get-breakpoints ()
|
|
||||||
"Get the list of breakpoints currently set."
|
|
||||||
(let ((string (haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
":show breaks")))
|
|
||||||
(if (string= string "No active breakpoints.\n")
|
|
||||||
(list)
|
|
||||||
(mapcar #'haskell-debug-parse-break-point
|
|
||||||
(haskell-debug-split-string string)))))
|
|
||||||
|
|
||||||
(defun haskell-debug-get-modules ()
|
|
||||||
"Get the list of modules currently set."
|
|
||||||
(let ((string (haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
":show modules")))
|
|
||||||
(if (string= string "")
|
|
||||||
(list)
|
|
||||||
(mapcar #'haskell-debug-parse-module
|
|
||||||
(haskell-debug-split-string string)))))
|
|
||||||
|
|
||||||
(defun haskell-debug-get-context ()
|
|
||||||
"Get the current context."
|
|
||||||
(let ((string (haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
":show context")))
|
|
||||||
(if (string= string "")
|
|
||||||
nil
|
|
||||||
(haskell-debug-parse-context string))))
|
|
||||||
|
|
||||||
(defun haskell-debug-get-history ()
|
|
||||||
"Get the step history."
|
|
||||||
(let ((string (haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
":history")))
|
|
||||||
(if (or (string= string "")
|
|
||||||
(string= string "Not stopped at a breakpoint\n"))
|
|
||||||
nil
|
|
||||||
(if (string= string "Empty history. Perhaps you forgot to use :trace?\n")
|
|
||||||
nil
|
|
||||||
(let ((entries (mapcar #'haskell-debug-parse-history-entry
|
|
||||||
(cl-remove-if (lambda (line) (or (string= "<end of history>" line)
|
|
||||||
(string= "..." line)))
|
|
||||||
(haskell-debug-split-string string)))))
|
|
||||||
(setq haskell-debug-history-cache
|
|
||||||
entries)
|
|
||||||
entries)))))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-bindings (modules breakpoints context)
|
|
||||||
"Insert a list of bindings."
|
|
||||||
(if breakpoints
|
|
||||||
(progn (haskell-debug-insert-binding "t" "trace an expression")
|
|
||||||
(haskell-debug-insert-binding "s" "step into an expression")
|
|
||||||
(haskell-debug-insert-binding "b" "breakpoint" t))
|
|
||||||
(progn
|
|
||||||
(when modules
|
|
||||||
(haskell-debug-insert-binding "b" "breakpoint"))
|
|
||||||
(when breakpoints
|
|
||||||
(haskell-debug-insert-binding "s" "step into an expression" t))))
|
|
||||||
(when breakpoints
|
|
||||||
(haskell-debug-insert-binding "d" "delete breakpoint"))
|
|
||||||
(when context
|
|
||||||
(haskell-debug-insert-binding "a" "abandon context")
|
|
||||||
(haskell-debug-insert-binding "c" "continue" t))
|
|
||||||
(when context
|
|
||||||
(haskell-debug-insert-binding "p" "previous step")
|
|
||||||
(haskell-debug-insert-binding "n" "next step" t))
|
|
||||||
(haskell-debug-insert-binding "g" "refresh" t)
|
|
||||||
(insert "\n"))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-current-context (context history)
|
|
||||||
"Insert the current context."
|
|
||||||
(haskell-debug-insert-header "Context")
|
|
||||||
(if context
|
|
||||||
(haskell-debug-insert-context context history)
|
|
||||||
(haskell-debug-insert-debug-finished))
|
|
||||||
(insert "\n"))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-breakpoints (breakpoints)
|
|
||||||
"insert the list of breakpoints."
|
|
||||||
(haskell-debug-insert-header "Breakpoints")
|
|
||||||
(if (null breakpoints)
|
|
||||||
(haskell-debug-insert-muted "No active breakpoints.")
|
|
||||||
(cl-loop for break in breakpoints
|
|
||||||
do (insert (propertize (format "%d"
|
|
||||||
(plist-get break :number))
|
|
||||||
'face `((:weight bold))
|
|
||||||
'break break)
|
|
||||||
(haskell-debug-muted " - ")
|
|
||||||
(propertize (plist-get break :module)
|
|
||||||
'break break
|
|
||||||
'break break)
|
|
||||||
(haskell-debug-muted
|
|
||||||
(format " (%d:%d)"
|
|
||||||
(plist-get (plist-get break :span) :start-line)
|
|
||||||
(plist-get (plist-get break :span) :start-col)))
|
|
||||||
"\n")))
|
|
||||||
(insert "\n"))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-modules (modules)
|
|
||||||
"Insert the list of modules."
|
|
||||||
(haskell-debug-insert-header "Modules")
|
|
||||||
(if (null modules)
|
|
||||||
(haskell-debug-insert-muted "No loaded modules.")
|
|
||||||
(progn (cl-loop for module in modules
|
|
||||||
do (insert (propertize (plist-get module :module)
|
|
||||||
'module module
|
|
||||||
'face `((:weight bold)))
|
|
||||||
(haskell-debug-muted " - ")
|
|
||||||
(propertize (file-name-nondirectory (plist-get module :path))
|
|
||||||
'module module))
|
|
||||||
do (insert "\n")))))
|
|
||||||
|
|
||||||
(defun haskell-debug-split-string (string)
|
|
||||||
"Split GHCi's line-based output, stripping the trailing newline."
|
|
||||||
(split-string string "\n" t))
|
|
||||||
|
|
||||||
(defun haskell-debug-parse-context (string)
|
|
||||||
"Parse the context."
|
|
||||||
(cond
|
|
||||||
((string-match "^--> \\(.+\\)\n \\(.+\\)" string)
|
|
||||||
(let ((name (match-string 1 string))
|
|
||||||
(stopped (haskell-debug-parse-stopped-at (match-string 2 string))))
|
|
||||||
(list :name name
|
|
||||||
:path (plist-get stopped :path)
|
|
||||||
:span (plist-get stopped :span))))))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-binding (binding desc &optional end)
|
|
||||||
"Insert a helpful keybinding."
|
|
||||||
(insert (propertize binding 'face 'haskell-debug-keybinding-face)
|
|
||||||
(haskell-debug-muted " - ")
|
|
||||||
desc
|
|
||||||
(if end
|
|
||||||
"\n"
|
|
||||||
(haskell-debug-muted ", "))))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-header (title)
|
|
||||||
"Insert a header title."
|
|
||||||
(insert (propertize title
|
|
||||||
'face 'haskell-debug-heading-face)
|
|
||||||
"\n\n"))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-context (context history)
|
|
||||||
"Insert the context and history."
|
|
||||||
(when context
|
|
||||||
(insert (propertize (plist-get context :name) 'face `((:weight bold)))
|
|
||||||
(haskell-debug-muted " - ")
|
|
||||||
(file-name-nondirectory (plist-get context :path))
|
|
||||||
(haskell-debug-muted " (stopped)")
|
|
||||||
"\n"))
|
|
||||||
(when haskell-debug-bindings-cache
|
|
||||||
(insert "\n")
|
|
||||||
(let ((bindings haskell-debug-bindings-cache))
|
|
||||||
(insert
|
|
||||||
(haskell-debug-get-span-string
|
|
||||||
(plist-get bindings :path)
|
|
||||||
(plist-get bindings :span)))
|
|
||||||
(insert "\n\n")
|
|
||||||
(cl-loop for binding in (plist-get bindings :types)
|
|
||||||
do (insert (haskell-fontify-as-mode binding 'haskell-mode)
|
|
||||||
"\n"))))
|
|
||||||
(let ((history (or history
|
|
||||||
(list (haskell-debug-make-fake-history context)))))
|
|
||||||
(when history
|
|
||||||
(insert "\n")
|
|
||||||
(haskell-debug-insert-history history))))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-debug-finished ()
|
|
||||||
"Insert message that no debugging is happening, but if there is
|
|
||||||
some old history, then display that."
|
|
||||||
(if haskell-debug-history-cache
|
|
||||||
(progn (haskell-debug-insert-muted "Finished debugging.")
|
|
||||||
(insert "\n")
|
|
||||||
(haskell-debug-insert-history haskell-debug-history-cache))
|
|
||||||
(haskell-debug-insert-muted "Not debugging right now.")))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-muted (text)
|
|
||||||
"Insert some muted text."
|
|
||||||
(insert (haskell-debug-muted text)
|
|
||||||
"\n"))
|
|
||||||
|
|
||||||
(defun haskell-debug-muted (text)
|
|
||||||
"Make some muted text."
|
|
||||||
(propertize text 'face 'haskell-debug-muted-face))
|
|
||||||
|
|
||||||
(defun haskell-debug-parse-logged (string)
|
|
||||||
"Parse the logged breakpoint."
|
|
||||||
(cond
|
|
||||||
((string= "no more logged breakpoints\n" string)
|
|
||||||
nil)
|
|
||||||
((string= "already at the beginning of the history\n" string)
|
|
||||||
nil)
|
|
||||||
(t
|
|
||||||
(with-temp-buffer
|
|
||||||
(insert string)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(list :path (progn (search-forward " at ")
|
|
||||||
(buffer-substring-no-properties
|
|
||||||
(point)
|
|
||||||
(1- (search-forward ":"))))
|
|
||||||
:span (haskell-debug-parse-span
|
|
||||||
(buffer-substring-no-properties
|
|
||||||
(point)
|
|
||||||
(line-end-position)))
|
|
||||||
:types (progn (forward-line)
|
|
||||||
(haskell-debug-split-string
|
|
||||||
(buffer-substring-no-properties
|
|
||||||
(point)
|
|
||||||
(point-max)))))))))
|
|
||||||
|
|
||||||
(defun haskell-debug-parse-stopped-at (string)
|
|
||||||
"Parse the location stopped at from the given string.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
Stopped at /home/foo/project/src/x.hs:6:25-36
|
|
||||||
|
|
||||||
"
|
|
||||||
(let ((index (string-match "Stopped at \\([^:]+\\):\\(.+\\)\n?"
|
|
||||||
string)))
|
|
||||||
(when index
|
|
||||||
(list :path (match-string 1 string)
|
|
||||||
:span (haskell-debug-parse-span (match-string 2 string))
|
|
||||||
:types (cdr (haskell-debug-split-string (substring string index)))))))
|
|
||||||
|
|
||||||
(defun haskell-debug-get-span-string (path span)
|
|
||||||
"Get the string from the PATH and the SPAN."
|
|
||||||
(save-window-excursion
|
|
||||||
(find-file path)
|
|
||||||
(buffer-substring
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- (plist-get span :start-line)))
|
|
||||||
(forward-char (1- (plist-get span :start-col)))
|
|
||||||
(point))
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- (plist-get span :end-line)))
|
|
||||||
(forward-char (plist-get span :end-col))
|
|
||||||
(point)))))
|
|
||||||
|
|
||||||
(defun haskell-debug-make-fake-history (context)
|
|
||||||
"Make a fake history item."
|
|
||||||
(list :index -1
|
|
||||||
:path (plist-get context :path)
|
|
||||||
:span (plist-get context :span)))
|
|
||||||
|
|
||||||
(defun haskell-debug-insert-history (history)
|
|
||||||
"Insert tracing HISTORY."
|
|
||||||
(let ((i (length history)))
|
|
||||||
(cl-loop for span in history
|
|
||||||
do (let ((string (haskell-debug-get-span-string
|
|
||||||
(plist-get span :path)
|
|
||||||
(plist-get span :span)))
|
|
||||||
(index (plist-get span :index)))
|
|
||||||
(insert (propertize (format "%4d" i)
|
|
||||||
'face 'haskell-debug-trace-number-face)
|
|
||||||
" "
|
|
||||||
(haskell-debug-preview-span
|
|
||||||
(plist-get span :span)
|
|
||||||
string
|
|
||||||
t)
|
|
||||||
"\n")
|
|
||||||
(setq i (1- i))))))
|
|
||||||
|
|
||||||
(defun haskell-debug-parse-span (string)
|
|
||||||
"Parse a source span from a string.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
(5,1)-(6,37)
|
|
||||||
6:25-36
|
|
||||||
5:20
|
|
||||||
|
|
||||||
People like to make other people's lives interesting by making
|
|
||||||
variances in source span notation."
|
|
||||||
(cond
|
|
||||||
((string-match "\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)"
|
|
||||||
string)
|
|
||||||
(list :start-line (string-to-number (match-string 1 string))
|
|
||||||
:start-col (string-to-number (match-string 2 string))
|
|
||||||
:end-line (string-to-number (match-string 1 string))
|
|
||||||
:end-col (string-to-number (match-string 3 string))))
|
|
||||||
((string-match "\\([0-9]+\\):\\([0-9]+\\)"
|
|
||||||
string)
|
|
||||||
(list :start-line (string-to-number (match-string 1 string))
|
|
||||||
:start-col (string-to-number (match-string 2 string))
|
|
||||||
:end-line (string-to-number (match-string 1 string))
|
|
||||||
:end-col (string-to-number (match-string 2 string))))
|
|
||||||
((string-match "(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))"
|
|
||||||
string)
|
|
||||||
(list :start-line (string-to-number (match-string 1 string))
|
|
||||||
:start-col (string-to-number (match-string 2 string))
|
|
||||||
:end-line (string-to-number (match-string 3 string))
|
|
||||||
:end-col (string-to-number (match-string 4 string))))
|
|
||||||
(t (error "Unable to parse source span from string: %s"
|
|
||||||
string))))
|
|
||||||
|
|
||||||
(defun haskell-debug-preview-span (span string &optional collapsed)
|
|
||||||
"Make a one-line preview of the given expression."
|
|
||||||
(with-temp-buffer
|
|
||||||
(haskell-mode)
|
|
||||||
(insert string)
|
|
||||||
(when (/= 0 (plist-get span :start-col))
|
|
||||||
(indent-rigidly (point-min)
|
|
||||||
(point-max)
|
|
||||||
1))
|
|
||||||
(if (fboundp 'font-lock-ensure)
|
|
||||||
(font-lock-ensure)
|
|
||||||
(with-no-warnings (font-lock-fontify-buffer)))
|
|
||||||
(when (/= 0 (plist-get span :start-col))
|
|
||||||
(indent-rigidly (point-min)
|
|
||||||
(point-max)
|
|
||||||
-1))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(if collapsed
|
|
||||||
(replace-regexp-in-string
|
|
||||||
"\n[ ]*"
|
|
||||||
(propertize " " 'face 'haskell-debug-newline-face)
|
|
||||||
(buffer-substring (point-min)
|
|
||||||
(point-max)))
|
|
||||||
(buffer-string))))
|
|
||||||
|
|
||||||
(defun haskell-debug-start (session)
|
|
||||||
"Start the debug mode."
|
|
||||||
(setq buffer-read-only t)
|
|
||||||
(haskell-session-assign session)
|
|
||||||
(haskell-debug/refresh))
|
|
||||||
|
|
||||||
(defun haskell-debug ()
|
|
||||||
"Start the debugger for the current Haskell (GHCi) session."
|
|
||||||
(interactive)
|
|
||||||
(let ((session (haskell-debug-session)))
|
|
||||||
(switch-to-buffer-other-window (haskell-debug-buffer-name session))
|
|
||||||
(unless (eq major-mode 'haskell-debug-mode)
|
|
||||||
(haskell-debug-mode)
|
|
||||||
(haskell-debug-start session))))
|
|
||||||
|
|
||||||
(defun haskell-debug-break (break)
|
|
||||||
"Set BREAK breakpoint in module at line/col."
|
|
||||||
(haskell-process-queue-without-filters
|
|
||||||
(haskell-debug-process)
|
|
||||||
(format ":break %s %s %d"
|
|
||||||
(plist-get break :module)
|
|
||||||
(plist-get (plist-get break :span) :start-line)
|
|
||||||
(plist-get (plist-get break :span) :start-col))))
|
|
||||||
|
|
||||||
(defun haskell-debug-navigate (direction)
|
|
||||||
"Navigate in DIRECTION \"back\" or \"forward\"."
|
|
||||||
(let ((string (haskell-process-queue-sync-request
|
|
||||||
(haskell-debug-process)
|
|
||||||
(concat ":" direction))))
|
|
||||||
(let ((bindings (haskell-debug-parse-logged string)))
|
|
||||||
(setq haskell-debug-bindings-cache
|
|
||||||
bindings)
|
|
||||||
(when (not bindings)
|
|
||||||
(message "No more %s results!" direction)))
|
|
||||||
(haskell-debug/refresh)))
|
|
||||||
|
|
||||||
(defun haskell-debug-session-debugging-p (session)
|
|
||||||
"Does the session have a debugging buffer open?"
|
|
||||||
(not (not (get-buffer (haskell-debug-buffer-name session)))))
|
|
||||||
|
|
||||||
(defun haskell-debug-highlight (path &optional span)
|
|
||||||
"Highlight the file at span."
|
|
||||||
(let ((p (make-overlay
|
|
||||||
(line-beginning-position)
|
|
||||||
(line-end-position))))
|
|
||||||
(overlay-put p 'face `((:background "#eee")))
|
|
||||||
(with-current-buffer
|
|
||||||
(if span
|
|
||||||
(save-window-excursion
|
|
||||||
(find-file path)
|
|
||||||
(current-buffer))
|
|
||||||
(find-file path)
|
|
||||||
(current-buffer))
|
|
||||||
(let ((o (when span
|
|
||||||
(make-overlay
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- (plist-get span :start-line)))
|
|
||||||
(forward-char (1- (plist-get span :start-col)))
|
|
||||||
(point))
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- (plist-get span :end-line)))
|
|
||||||
(forward-char (plist-get span :end-col))
|
|
||||||
(point))))))
|
|
||||||
(when o
|
|
||||||
(overlay-put o 'face `((:background "#eee"))))
|
|
||||||
(sit-for 0.5)
|
|
||||||
(when o
|
|
||||||
(delete-overlay o))
|
|
||||||
(delete-overlay p)))))
|
|
||||||
|
|
||||||
(defun haskell-debug-parse-history-entry (string)
|
|
||||||
"Parse a history entry."
|
|
||||||
(if (string-match "^\\([-0-9]+\\)[ ]+:[ ]+\\([A-Za-z0-9_':]+\\)[ ]+(\\([^:]+\\):\\(.+?\\))$"
|
|
||||||
string)
|
|
||||||
(list :index (string-to-number (match-string 1 string))
|
|
||||||
:name (match-string 2 string)
|
|
||||||
:path (match-string 3 string)
|
|
||||||
:span (haskell-debug-parse-span (match-string 4 string)))
|
|
||||||
(error "Unable to parse history entry: %s" string)))
|
|
||||||
|
|
||||||
(defun haskell-debug-parse-module (string)
|
|
||||||
"Parse a module and path.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
X ( /home/foo/X.hs, interpreted )
|
|
||||||
|
|
||||||
"
|
|
||||||
(if (string-match "^\\([^ ]+\\)[ ]+( \\([^ ]+?\\), [a-z]+ )$"
|
|
||||||
string)
|
|
||||||
(list :module (match-string 1 string)
|
|
||||||
:path (match-string 2 string))
|
|
||||||
(error "Unable to parse module from string: %s"
|
|
||||||
string)))
|
|
||||||
|
|
||||||
(defun haskell-debug-parse-break-point (string)
|
|
||||||
"Parse a breakpoint number, module and location from a string.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
[13] Main /home/foo/src/x.hs:(5,1)-(6,37)
|
|
||||||
|
|
||||||
"
|
|
||||||
(if (string-match "^\\[\\([0-9]+\\)\\] \\([^ ]+\\) \\([^:]+\\):\\(.+\\)$"
|
|
||||||
string)
|
|
||||||
(list :number (string-to-number (match-string 1 string))
|
|
||||||
:module (match-string 2 string)
|
|
||||||
:path (match-string 3 string)
|
|
||||||
:span (haskell-debug-parse-span (match-string 4 string)))
|
|
||||||
(error "Unable to parse breakpoint from string: %s"
|
|
||||||
string)))
|
|
||||||
|
|
||||||
(provide 'haskell-debug)
|
|
||||||
|
|
||||||
;;; haskell-debug.el ends here
|
|
Binary file not shown.
@@ -1,604 +0,0 @@
|
|||||||
;;; haskell-decl-scan.el --- Declaration scanning module for Haskell Mode
|
|
||||||
|
|
||||||
;; Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
|
|
||||||
;; Copyright (C) 1997-1998 Graeme E Moss
|
|
||||||
|
|
||||||
;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk>
|
|
||||||
;; Maintainer: Stefan Monnier <monnier@gnu.org>
|
|
||||||
;; Keywords: declarations menu files Haskell
|
|
||||||
;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-decl-scan.el?rev=HEAD
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Purpose:
|
|
||||||
;;
|
|
||||||
;; Top-level declarations are scanned and placed in a menu. Supports
|
|
||||||
;; full Latin1 Haskell 1.4 as well as literate scripts.
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; Installation:
|
|
||||||
;;
|
|
||||||
;; To turn declaration scanning on for all Haskell buffers under the
|
|
||||||
;; Haskell mode of Moss&Thorn, add this to .emacs:
|
|
||||||
;;
|
|
||||||
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
|
|
||||||
;;
|
|
||||||
;; Otherwise, call `turn-on-haskell-decl-scan'.
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; Customisation:
|
|
||||||
;;
|
|
||||||
;; M-x customize-group haskell-decl-scan
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; History:
|
|
||||||
;;
|
|
||||||
;; If you have any problems or suggestions, after consulting the list
|
|
||||||
;; below, email gem@cs.york.ac.uk quoting the version of the library
|
|
||||||
;; you are using, the version of Emacs you are using, and a small
|
|
||||||
;; example of the problem or suggestion. Note that this library
|
|
||||||
;; requires a reasonably recent version of Emacs.
|
|
||||||
;;
|
|
||||||
;; Uses `imenu' under Emacs.
|
|
||||||
;;
|
|
||||||
;; Version 1.2:
|
|
||||||
;; Added support for LaTeX-style literate scripts.
|
|
||||||
;;
|
|
||||||
;; Version 1.1:
|
|
||||||
;; Use own syntax table. Fixed bug for very small buffers. Use
|
|
||||||
;; markers instead of pointers (markers move with the text).
|
|
||||||
;;
|
|
||||||
;; Version 1.0:
|
|
||||||
;; Brought over from Haskell mode v1.1.
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; Present Limitations/Future Work (contributions are most welcome!):
|
|
||||||
;;
|
|
||||||
;; . Declarations requiring information extending beyond starting line
|
|
||||||
;; don't get scanned properly, eg.
|
|
||||||
;; > class Eq a =>
|
|
||||||
;; > Test a
|
|
||||||
;;
|
|
||||||
;; . Comments placed in the midst of the first few lexemes of a
|
|
||||||
;; declaration will cause havoc, eg.
|
|
||||||
;; > infixWithComments :: Int -> Int -> Int
|
|
||||||
;; > x {-nastyComment-} `infixWithComments` y = x + y
|
|
||||||
;; but are not worth worrying about.
|
|
||||||
;;
|
|
||||||
;; . Would be nice to scan other top-level declarations such as
|
|
||||||
;; methods of a class, datatype field labels... any more?
|
|
||||||
;;
|
|
||||||
;; . Support for GreenCard?
|
|
||||||
;;
|
|
||||||
;; . Re-running (literate-)haskell-imenu should not cause the problems
|
|
||||||
;; that it does. The ability to turn off scanning would also be
|
|
||||||
;; useful. (Note that re-running (literate-)haskell-mode seems to
|
|
||||||
;; cause no problems.)
|
|
||||||
|
|
||||||
;; All functions/variables start with
|
|
||||||
;; `(turn-(on/off)-)haskell-decl-scan' or `haskell-ds-'.
|
|
||||||
|
|
||||||
;; The imenu support is based on code taken from `hugs-mode',
|
|
||||||
;; thanks go to Chris Van Humbeeck.
|
|
||||||
|
|
||||||
;; Version.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'haskell-mode)
|
|
||||||
(require 'syntax)
|
|
||||||
(require 'imenu)
|
|
||||||
|
|
||||||
(defgroup haskell-decl-scan nil
|
|
||||||
"Haskell declaration scanning (`imenu' support)."
|
|
||||||
:link '(custom-manual "(haskell-mode)haskell-decl-scan-mode")
|
|
||||||
:group 'haskell
|
|
||||||
:prefix "haskell-decl-scan-")
|
|
||||||
|
|
||||||
(defcustom haskell-decl-scan-bindings-as-variables nil
|
|
||||||
"Whether to put top-level value bindings into a \"Variables\" category."
|
|
||||||
:group 'haskell-decl-scan
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
(defcustom haskell-decl-scan-add-to-menubar t
|
|
||||||
"Whether to add a \"Declarations\" menu entry to menu bar."
|
|
||||||
:group 'haskell-decl-scan
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; General declaration scanning functions.
|
|
||||||
|
|
||||||
(defvar haskell-ds-start-keywords-re
|
|
||||||
(concat "\\(\\<"
|
|
||||||
"class\\|data\\|i\\(mport\\|n\\(fix\\(\\|[lr]\\)\\|stance\\)\\)\\|"
|
|
||||||
"module\\|primitive\\|type\\|newtype"
|
|
||||||
"\\)\\>")
|
|
||||||
"Keywords that may start a declaration.")
|
|
||||||
|
|
||||||
(defvar haskell-ds-syntax-table
|
|
||||||
(let ((table (copy-syntax-table haskell-mode-syntax-table)))
|
|
||||||
(modify-syntax-entry ?\' "w" table)
|
|
||||||
(modify-syntax-entry ?_ "w" table)
|
|
||||||
(modify-syntax-entry ?\\ "_" table)
|
|
||||||
table)
|
|
||||||
"Syntax table used for Haskell declaration scanning.")
|
|
||||||
|
|
||||||
|
|
||||||
(defun haskell-ds-get-variable (prefix)
|
|
||||||
"Return variable involved in value binding or type signature.
|
|
||||||
Assumes point is looking at the regexp PREFIX followed by the
|
|
||||||
start of a declaration (perhaps in the middle of a series of
|
|
||||||
declarations concerning a single variable). Otherwise return nil.
|
|
||||||
Point is not changed."
|
|
||||||
;; I think I can now handle all declarations bar those with comments
|
|
||||||
;; nested before the second lexeme.
|
|
||||||
(save-excursion
|
|
||||||
(with-syntax-table haskell-ds-syntax-table
|
|
||||||
(if (looking-at prefix) (goto-char (match-end 0)))
|
|
||||||
;; Keyword.
|
|
||||||
(if (looking-at haskell-ds-start-keywords-re)
|
|
||||||
nil
|
|
||||||
(or ;; Parenthesized symbolic variable.
|
|
||||||
(and (looking-at "(\\(\\s_+\\))") (match-string-no-properties 1))
|
|
||||||
;; General case.
|
|
||||||
(if (looking-at
|
|
||||||
(if (eq ?\( (char-after))
|
|
||||||
;; Skip paranthesised expression.
|
|
||||||
(progn
|
|
||||||
(forward-sexp)
|
|
||||||
;; Repeating this code and avoiding moving point if
|
|
||||||
;; possible speeds things up.
|
|
||||||
"\\(\\'\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)")
|
|
||||||
"\\(\\sw+\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)"))
|
|
||||||
(let ((match2 (match-string-no-properties 2)))
|
|
||||||
;; Weed out `::', `∷',`=' and `|' from potential infix
|
|
||||||
;; symbolic variable.
|
|
||||||
(if (member match2 '("::" "∷" "=" "|"))
|
|
||||||
;; Variable identifier.
|
|
||||||
(match-string-no-properties 1)
|
|
||||||
(if (eq (aref match2 0) ?\`)
|
|
||||||
;; Infix variable identifier.
|
|
||||||
(match-string-no-properties 3)
|
|
||||||
;; Infix symbolic variable.
|
|
||||||
match2))))
|
|
||||||
;; Variable identifier.
|
|
||||||
(and (looking-at "\\sw+") (match-string-no-properties 0)))))))
|
|
||||||
|
|
||||||
(defun haskell-ds-move-to-start-regexp (inc regexp)
|
|
||||||
"Move to beginning of line that succeeds/precedes (INC = 1/-1)
|
|
||||||
current line that starts with REGEXP and is not in `font-lock-comment-face'."
|
|
||||||
;; Making this defsubst instead of defun appears to have little or
|
|
||||||
;; no effect on efficiency. It is probably not called enough to do
|
|
||||||
;; so.
|
|
||||||
(while (and (= (forward-line inc) 0)
|
|
||||||
(or (not (looking-at regexp))
|
|
||||||
(eq (get-text-property (point) 'face)
|
|
||||||
'font-lock-comment-face)))))
|
|
||||||
|
|
||||||
(defun haskell-ds-move-to-start-regexp-skipping-comments (inc regexp)
|
|
||||||
"Like haskell-ds-move-to-start-regexp, but uses syntax-ppss to
|
|
||||||
skip comments"
|
|
||||||
(let (p)
|
|
||||||
(cl-loop
|
|
||||||
do (setq p (point))
|
|
||||||
(haskell-ds-move-to-start-regexp inc regexp)
|
|
||||||
while (and (nth 4 (syntax-ppss))
|
|
||||||
(/= p (point))))))
|
|
||||||
|
|
||||||
(defvar literate-haskell-ds-line-prefix "> ?"
|
|
||||||
"Regexp matching start of a line of Bird-style literate code.
|
|
||||||
Current value is \"> \" as we assume top-level declarations start
|
|
||||||
at column 3. Must not contain the special \"^\" regexp as we may
|
|
||||||
not use the regexp at the start of a regexp string. Note this is
|
|
||||||
only for `imenu' support.")
|
|
||||||
|
|
||||||
(defvar haskell-ds-start-decl-re "\\(\\sw\\|(\\)"
|
|
||||||
"The regexp that starts a Haskell declaration.")
|
|
||||||
|
|
||||||
(defvar literate-haskell-ds-start-decl-re
|
|
||||||
(concat literate-haskell-ds-line-prefix haskell-ds-start-decl-re)
|
|
||||||
"The regexp that starts a Bird-style literate Haskell declaration.")
|
|
||||||
|
|
||||||
(defun haskell-ds-move-to-decl (direction bird-literate fix)
|
|
||||||
"General function for moving to the start of a declaration,
|
|
||||||
either forwards or backwards from point, with normal or with Bird-style
|
|
||||||
literate scripts. If DIRECTION is t, then forward, else backward. If
|
|
||||||
BIRD-LITERATE is t, then treat as Bird-style literate scripts, else
|
|
||||||
normal scripts. Returns point if point is left at the start of a
|
|
||||||
declaration, and nil otherwise, ie. because point is at the beginning
|
|
||||||
or end of the buffer and no declaration starts there. If FIX is t,
|
|
||||||
then point does not move if already at the start of a declaration."
|
|
||||||
;; As `haskell-ds-get-variable' cannot separate an infix variable
|
|
||||||
;; identifier out of a value binding with non-alphanumeric first
|
|
||||||
;; argument, this function will treat such value bindings as
|
|
||||||
;; separate from the declarations surrounding it.
|
|
||||||
(let ( ;; The variable typed or bound in the current series of
|
|
||||||
;; declarations.
|
|
||||||
name
|
|
||||||
;; The variable typed or bound in the new declaration.
|
|
||||||
newname
|
|
||||||
;; Hack to solve hard problem for Bird-style literate scripts
|
|
||||||
;; that start with a declaration. We are in the abyss if
|
|
||||||
;; point is before start of this declaration.
|
|
||||||
abyss
|
|
||||||
(line-prefix (if bird-literate literate-haskell-ds-line-prefix ""))
|
|
||||||
;; The regexp to match for the start of a declaration.
|
|
||||||
(start-decl-re (if bird-literate
|
|
||||||
literate-haskell-ds-start-decl-re
|
|
||||||
haskell-ds-start-decl-re))
|
|
||||||
(increment (if direction 1 -1))
|
|
||||||
(bound (if direction (point-max) (point-min))))
|
|
||||||
;; Change syntax table.
|
|
||||||
(with-syntax-table haskell-ds-syntax-table
|
|
||||||
;; move to beginning of line that starts the "current
|
|
||||||
;; declaration" (dependent on DIRECTION and FIX), and then get
|
|
||||||
;; the variable typed or bound by this declaration, if any.
|
|
||||||
(let ( ;; Where point was at call of function.
|
|
||||||
(here (point))
|
|
||||||
;; Where the declaration on this line (if any) starts.
|
|
||||||
(start (progn
|
|
||||||
(beginning-of-line)
|
|
||||||
;; Checking the face to ensure a declaration starts
|
|
||||||
;; here seems to be the only addition to make this
|
|
||||||
;; module support LaTeX-style literate scripts.
|
|
||||||
(if (and (looking-at start-decl-re)
|
|
||||||
(not (elt (syntax-ppss) 4)))
|
|
||||||
(match-beginning 1)))))
|
|
||||||
(if (and start
|
|
||||||
;; This complicated boolean determines whether we
|
|
||||||
;; should include the declaration that starts on the
|
|
||||||
;; current line as the "current declaration" or not.
|
|
||||||
(or (and (or (and direction (not fix))
|
|
||||||
(and (not direction) fix))
|
|
||||||
(>= here start))
|
|
||||||
(and (or (and direction fix)
|
|
||||||
(and (not direction) (not fix)))
|
|
||||||
(> here start))))
|
|
||||||
;; If so, we are already at start of the current line, so
|
|
||||||
;; do nothing.
|
|
||||||
()
|
|
||||||
;; If point was before start of a declaration on the first
|
|
||||||
;; line of the buffer (possible for Bird-style literate
|
|
||||||
;; scripts) then we are in the abyss.
|
|
||||||
(if (and start (bobp))
|
|
||||||
(setq abyss t)
|
|
||||||
;; Otherwise we move to the start of the first declaration
|
|
||||||
;; on a line preceding the current one, skipping comments
|
|
||||||
(haskell-ds-move-to-start-regexp-skipping-comments -1 start-decl-re))))
|
|
||||||
;; If we are in the abyss, position and return as appropriate.
|
|
||||||
(if abyss
|
|
||||||
(if (not direction)
|
|
||||||
nil
|
|
||||||
(re-search-forward (concat "\\=" line-prefix) nil t)
|
|
||||||
(point))
|
|
||||||
;; Get the variable typed or bound by this declaration, if any.
|
|
||||||
(setq name (haskell-ds-get-variable line-prefix))
|
|
||||||
(if (not name)
|
|
||||||
;; If no such variable, stop at the start of this
|
|
||||||
;; declaration if moving backward, or move to the next
|
|
||||||
;; declaration if moving forward.
|
|
||||||
(if direction
|
|
||||||
(haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re))
|
|
||||||
;; If there is a variable, find the first
|
|
||||||
;; succeeding/preceding declaration that does not type or
|
|
||||||
;; bind it. Check for reaching start/end of buffer and
|
|
||||||
;; comments.
|
|
||||||
(haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re)
|
|
||||||
(while (and (/= (point) bound)
|
|
||||||
(and (setq newname (haskell-ds-get-variable line-prefix))
|
|
||||||
(string= name newname)))
|
|
||||||
(setq name newname)
|
|
||||||
(haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re))
|
|
||||||
;; If we are going backward, and have either reached a new
|
|
||||||
;; declaration or the beginning of a buffer that does not
|
|
||||||
;; start with a declaration, move forward to start of next
|
|
||||||
;; declaration (which must exist). Otherwise, we are done.
|
|
||||||
(if (and (not direction)
|
|
||||||
(or (and (looking-at start-decl-re)
|
|
||||||
(not (string= name
|
|
||||||
;; Note we must not use
|
|
||||||
;; newname here as this may
|
|
||||||
;; not have been set if we
|
|
||||||
;; have reached the beginning
|
|
||||||
;; of the buffer.
|
|
||||||
(haskell-ds-get-variable
|
|
||||||
line-prefix))))
|
|
||||||
(and (not (looking-at start-decl-re))
|
|
||||||
(bobp))))
|
|
||||||
(haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re)))
|
|
||||||
;; Store whether we are at the start of a declaration or not.
|
|
||||||
;; Used to calculate final result.
|
|
||||||
(let ((at-start-decl (looking-at start-decl-re)))
|
|
||||||
;; If we are at the beginning of a line, move over
|
|
||||||
;; line-prefix, if present at point.
|
|
||||||
(if (bolp)
|
|
||||||
(re-search-forward (concat "\\=" line-prefix) (point-max) t))
|
|
||||||
;; Return point if at the start of a declaration and nil
|
|
||||||
;; otherwise.
|
|
||||||
(if at-start-decl (point) nil))))))
|
|
||||||
|
|
||||||
(defun haskell-ds-bird-p ()
|
|
||||||
(and (boundp 'haskell-literate) (eq haskell-literate 'bird)))
|
|
||||||
|
|
||||||
(defun haskell-ds-backward-decl ()
|
|
||||||
"Move backward to the first character that starts a top-level declaration.
|
|
||||||
A series of declarations concerning one variable is treated as one
|
|
||||||
declaration by this function. So, if point is within a top-level
|
|
||||||
declaration then move it to the start of that declaration. If point
|
|
||||||
is already at the start of a top-level declaration, then move it to
|
|
||||||
the start of the preceding declaration. Returns point if point is
|
|
||||||
left at the start of a declaration, and nil otherwise, ie. because
|
|
||||||
point is at the beginning of the buffer and no declaration starts
|
|
||||||
there."
|
|
||||||
(interactive)
|
|
||||||
(haskell-ds-move-to-decl nil (haskell-ds-bird-p) nil))
|
|
||||||
|
|
||||||
(defun haskell-ds-forward-decl ()
|
|
||||||
"As `haskell-ds-backward-decl' but forward."
|
|
||||||
(interactive)
|
|
||||||
(haskell-ds-move-to-decl t (haskell-ds-bird-p) nil))
|
|
||||||
|
|
||||||
(defun haskell-ds-generic-find-next-decl (bird-literate)
|
|
||||||
"Find the name, position and type of the declaration at or after point.
|
|
||||||
Return ((NAME . (START-POSITION . NAME-POSITION)) . TYPE)
|
|
||||||
if one exists and nil otherwise. The start-position is at the start
|
|
||||||
of the declaration, and the name-position is at the start of the name
|
|
||||||
of the declaration. The name is a string, the positions are buffer
|
|
||||||
positions and the type is one of the symbols \"variable\", \"datatype\",
|
|
||||||
\"class\", \"import\" and \"instance\"."
|
|
||||||
(let ( ;; The name, type and name-position of the declaration to
|
|
||||||
;; return.
|
|
||||||
name
|
|
||||||
type
|
|
||||||
name-pos
|
|
||||||
;; Buffer positions marking the start and end of the space
|
|
||||||
;; containing a declaration.
|
|
||||||
start
|
|
||||||
end)
|
|
||||||
;; Change to declaration scanning syntax.
|
|
||||||
(with-syntax-table haskell-ds-syntax-table
|
|
||||||
;; Stop when we are at the end of the buffer or when a valid
|
|
||||||
;; declaration is grabbed.
|
|
||||||
(while (not (or (eobp) name))
|
|
||||||
;; Move forward to next declaration at or after point.
|
|
||||||
(haskell-ds-move-to-decl t bird-literate t)
|
|
||||||
;; Start and end of search space is currently just the starting
|
|
||||||
;; line of the declaration.
|
|
||||||
(setq start (point)
|
|
||||||
end (line-end-position))
|
|
||||||
(cond
|
|
||||||
;; If the start of the top-level declaration does not begin
|
|
||||||
;; with a starting keyword, then (if legal) must be a type
|
|
||||||
;; signature or value binding, and the variable concerned is
|
|
||||||
;; grabbed.
|
|
||||||
((not (looking-at haskell-ds-start-keywords-re))
|
|
||||||
(setq name (haskell-ds-get-variable ""))
|
|
||||||
(if name
|
|
||||||
(progn
|
|
||||||
(setq type 'variable)
|
|
||||||
(re-search-forward (regexp-quote name) end t)
|
|
||||||
(setq name-pos (match-beginning 0)))))
|
|
||||||
;; User-defined datatype declaration.
|
|
||||||
((re-search-forward "\\=\\(data\\|newtype\\|type\\)\\>" end t)
|
|
||||||
(re-search-forward "=>" end t)
|
|
||||||
(if (looking-at "[ \t]*\\(\\sw+\\)")
|
|
||||||
(progn
|
|
||||||
(setq name (match-string-no-properties 1))
|
|
||||||
(setq name-pos (match-beginning 1))
|
|
||||||
(setq type 'datatype))))
|
|
||||||
;; Class declaration.
|
|
||||||
((re-search-forward "\\=class\\>" end t)
|
|
||||||
(re-search-forward "=>" end t)
|
|
||||||
(if (looking-at "[ \t]*\\(\\sw+\\)")
|
|
||||||
(progn
|
|
||||||
(setq name (match-string-no-properties 1))
|
|
||||||
(setq name-pos (match-beginning 1))
|
|
||||||
(setq type 'class))))
|
|
||||||
;; Import declaration.
|
|
||||||
((looking-at "import[ \t]+\\(?:safe[\t ]+\\)?\\(?:qualified[ \t]+\\)?\\(?:\"[^\"]*\"[\t ]+\\)?\\(\\(?:\\sw\\|.\\)+\\)")
|
|
||||||
(setq name (match-string-no-properties 1))
|
|
||||||
(setq name-pos (match-beginning 1))
|
|
||||||
(setq type 'import))
|
|
||||||
;; Instance declaration.
|
|
||||||
((re-search-forward "\\=instance[ \t]+" end t)
|
|
||||||
(re-search-forward "=>[ \t]+" end t)
|
|
||||||
;; The instance "title" starts just after the `instance' (and
|
|
||||||
;; any context) and finishes just before the _first_ `where'
|
|
||||||
;; if one exists. This solution is ugly, but I can't find a
|
|
||||||
;; nicer one---a simple regexp will pick up the last `where',
|
|
||||||
;; which may be rare but nevertheless...
|
|
||||||
(setq name-pos (point))
|
|
||||||
(setq name (buffer-substring-no-properties
|
|
||||||
(point)
|
|
||||||
(progn
|
|
||||||
;; Look for a `where'.
|
|
||||||
(if (re-search-forward "\\<where\\>" end t)
|
|
||||||
;; Move back to just before the `where'.
|
|
||||||
(progn
|
|
||||||
(re-search-backward "\\s-where")
|
|
||||||
(point))
|
|
||||||
;; No `where' so move to last non-whitespace
|
|
||||||
;; before `end'.
|
|
||||||
(progn
|
|
||||||
(goto-char end)
|
|
||||||
(skip-chars-backward " \t")
|
|
||||||
(point))))))
|
|
||||||
;; If we did not manage to extract a name, cancel this
|
|
||||||
;; declaration (eg. when line ends in "=> ").
|
|
||||||
(if (string-match "^[ \t]*$" name) (setq name nil))
|
|
||||||
(setq type 'instance)))
|
|
||||||
;; Move past start of current declaration.
|
|
||||||
(goto-char end))
|
|
||||||
;; If we have a valid declaration then return it, otherwise return
|
|
||||||
;; nil.
|
|
||||||
(if name
|
|
||||||
(cons (cons name (cons (copy-marker start t) (copy-marker name-pos t)))
|
|
||||||
type)
|
|
||||||
nil))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; Declaration scanning via `imenu'.
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-ds-create-imenu-index ()
|
|
||||||
"Function for finding `imenu' declarations in Haskell mode.
|
|
||||||
Finds all declarations (classes, variables, imports, instances and
|
|
||||||
datatypes) in a Haskell file for the `imenu' package."
|
|
||||||
;; Each list has elements of the form `(INDEX-NAME . INDEX-POSITION)'.
|
|
||||||
;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'.
|
|
||||||
(let* ((bird-literate (haskell-ds-bird-p))
|
|
||||||
(index-alist '())
|
|
||||||
(index-class-alist '()) ;; Classes
|
|
||||||
(index-var-alist '()) ;; Variables
|
|
||||||
(index-imp-alist '()) ;; Imports
|
|
||||||
(index-inst-alist '()) ;; Instances
|
|
||||||
(index-type-alist '()) ;; Datatypes
|
|
||||||
;; Variables for showing progress.
|
|
||||||
(bufname (buffer-name))
|
|
||||||
(divisor-of-progress (max 1 (/ (buffer-size) 100)))
|
|
||||||
;; The result we wish to return.
|
|
||||||
result)
|
|
||||||
(goto-char (point-min))
|
|
||||||
;; Loop forwards from the beginning of the buffer through the
|
|
||||||
;; starts of the top-level declarations.
|
|
||||||
(while (< (point) (point-max))
|
|
||||||
(message "Scanning declarations in %s... (%3d%%)" bufname
|
|
||||||
(/ (- (point) (point-min)) divisor-of-progress))
|
|
||||||
;; Grab the next declaration.
|
|
||||||
(setq result (haskell-ds-generic-find-next-decl bird-literate))
|
|
||||||
(if result
|
|
||||||
;; If valid, extract the components of the result.
|
|
||||||
(let* ((name-posns (car result))
|
|
||||||
(name (car name-posns))
|
|
||||||
(posns (cdr name-posns))
|
|
||||||
(start-pos (car posns))
|
|
||||||
(type (cdr result))
|
|
||||||
;; Place `(name . start-pos)' in the correct alist.
|
|
||||||
(sym (cdr (assq type
|
|
||||||
'((variable . index-var-alist)
|
|
||||||
(datatype . index-type-alist)
|
|
||||||
(class . index-class-alist)
|
|
||||||
(import . index-imp-alist)
|
|
||||||
(instance . index-inst-alist))))))
|
|
||||||
(set sym (cons (cons name start-pos) (symbol-value sym))))))
|
|
||||||
;; Now sort all the lists, label them, and place them in one list.
|
|
||||||
(message "Sorting declarations in %s..." bufname)
|
|
||||||
(when index-type-alist
|
|
||||||
(push (cons "Datatypes"
|
|
||||||
(sort index-type-alist 'haskell-ds-imenu-label-cmp))
|
|
||||||
index-alist))
|
|
||||||
(when index-inst-alist
|
|
||||||
(push (cons "Instances"
|
|
||||||
(sort index-inst-alist 'haskell-ds-imenu-label-cmp))
|
|
||||||
index-alist))
|
|
||||||
(when index-imp-alist
|
|
||||||
(push (cons "Imports"
|
|
||||||
(sort index-imp-alist 'haskell-ds-imenu-label-cmp))
|
|
||||||
index-alist))
|
|
||||||
(when index-class-alist
|
|
||||||
(push (cons "Classes"
|
|
||||||
(sort index-class-alist 'haskell-ds-imenu-label-cmp))
|
|
||||||
index-alist))
|
|
||||||
(when index-var-alist
|
|
||||||
(if haskell-decl-scan-bindings-as-variables
|
|
||||||
(push (cons "Variables"
|
|
||||||
(sort index-var-alist 'haskell-ds-imenu-label-cmp))
|
|
||||||
index-alist)
|
|
||||||
(setq index-alist (append index-alist
|
|
||||||
(sort index-var-alist 'haskell-ds-imenu-label-cmp)))))
|
|
||||||
(message "Sorting declarations in %s...done" bufname)
|
|
||||||
;; Return the alist.
|
|
||||||
index-alist))
|
|
||||||
|
|
||||||
(defun haskell-ds-imenu-label-cmp (el1 el2)
|
|
||||||
"Predicate to compare labels in lists from `haskell-ds-create-imenu-index'."
|
|
||||||
(string< (car el1) (car el2)))
|
|
||||||
|
|
||||||
(defun haskell-ds-imenu ()
|
|
||||||
"Install `imenu' for Haskell scripts."
|
|
||||||
(setq imenu-create-index-function 'haskell-ds-create-imenu-index)
|
|
||||||
(when haskell-decl-scan-add-to-menubar
|
|
||||||
(imenu-add-to-menubar "Declarations")))
|
|
||||||
|
|
||||||
;; The main functions to turn on declaration scanning.
|
|
||||||
;;;###autoload
|
|
||||||
(defun turn-on-haskell-decl-scan ()
|
|
||||||
"Unconditionally activate `haskell-decl-scan-mode'."
|
|
||||||
(interactive)
|
|
||||||
(haskell-decl-scan-mode))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-minor-mode haskell-decl-scan-mode
|
|
||||||
"Toggle Haskell declaration scanning minor mode on or off.
|
|
||||||
With a prefix argument ARG, enable minor mode if ARG is
|
|
||||||
positive, and disable it otherwise. If called from Lisp, enable
|
|
||||||
the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'.
|
|
||||||
|
|
||||||
See also info node `(haskell-mode)haskell-decl-scan-mode' for
|
|
||||||
more details about this minor mode.
|
|
||||||
|
|
||||||
Top-level declarations are scanned and listed in the menu item
|
|
||||||
\"Declarations\" (if enabled via option
|
|
||||||
`haskell-decl-scan-add-to-menubar'). Selecting an item from this
|
|
||||||
menu will take point to the start of the declaration.
|
|
||||||
|
|
||||||
\\[beginning-of-defun] and \\[end-of-defun] move forward and backward to the start of a declaration.
|
|
||||||
|
|
||||||
This may link with `haskell-doc-mode'.
|
|
||||||
|
|
||||||
For non-literate and LaTeX-style literate scripts, we assume the
|
|
||||||
common convention that top-level declarations start at the first
|
|
||||||
column. For Bird-style literate scripts, we assume the common
|
|
||||||
convention that top-level declarations start at the third column,
|
|
||||||
ie. after \"> \".
|
|
||||||
|
|
||||||
Anything in `font-lock-comment-face' is not considered for a
|
|
||||||
declaration. Therefore, using Haskell font locking with comments
|
|
||||||
coloured in `font-lock-comment-face' improves declaration scanning.
|
|
||||||
|
|
||||||
Literate Haskell scripts are supported: If the value of
|
|
||||||
`haskell-literate' (set automatically by `literate-haskell-mode')
|
|
||||||
is `bird', a Bird-style literate script is assumed. If it is nil
|
|
||||||
or `tex', a non-literate or LaTeX-style literate script is
|
|
||||||
assumed, respectively.
|
|
||||||
|
|
||||||
Invokes `haskell-decl-scan-mode-hook' on activation."
|
|
||||||
:group 'haskell-decl-scan
|
|
||||||
|
|
||||||
(kill-local-variable 'beginning-of-defun-function)
|
|
||||||
(kill-local-variable 'end-of-defun-function)
|
|
||||||
(kill-local-variable 'imenu-create-index-function)
|
|
||||||
(unless haskell-decl-scan-mode
|
|
||||||
;; How can we cleanly remove the "Declarations" menu?
|
|
||||||
(when haskell-decl-scan-add-to-menubar
|
|
||||||
(local-set-key [menu-bar index] nil)))
|
|
||||||
|
|
||||||
(when haskell-decl-scan-mode
|
|
||||||
(set (make-local-variable 'beginning-of-defun-function)
|
|
||||||
'haskell-ds-backward-decl)
|
|
||||||
(set (make-local-variable 'end-of-defun-function)
|
|
||||||
'haskell-ds-forward-decl)
|
|
||||||
(haskell-ds-imenu)))
|
|
||||||
|
|
||||||
|
|
||||||
;; Provide ourselves:
|
|
||||||
|
|
||||||
(provide 'haskell-decl-scan)
|
|
||||||
|
|
||||||
;;; haskell-decl-scan.el ends here
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,709 +0,0 @@
|
|||||||
;;; haskell-font-lock.el --- Font locking module for Haskell Mode
|
|
||||||
|
|
||||||
;; Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
|
||||||
;; Copyright 1997-1998 Graeme E Moss, and Tommy Thorn
|
|
||||||
|
|
||||||
;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk>
|
|
||||||
;; 1997-1998 Tommy Thorn <thorn@irisa.fr>
|
|
||||||
;; 2003 Dave Love <fx@gnu.org>
|
|
||||||
;; Keywords: faces files Haskell
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Purpose:
|
|
||||||
;;
|
|
||||||
;; To support fontification of standard Haskell keywords, symbols,
|
|
||||||
;; functions, etc. Supports full Haskell 1.4 as well as LaTeX- and
|
|
||||||
;; Bird-style literate scripts.
|
|
||||||
;;
|
|
||||||
;; Installation:
|
|
||||||
;;
|
|
||||||
;; To turn font locking on for all Haskell buffers under the Haskell
|
|
||||||
;; mode of Moss&Thorn, add this to .emacs:
|
|
||||||
;;
|
|
||||||
;; (add-hook 'haskell-mode-hook 'turn-on-haskell-font-lock)
|
|
||||||
;;
|
|
||||||
;; Otherwise, call `turn-on-haskell-font-lock'.
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; Customisation:
|
|
||||||
;;
|
|
||||||
;; The colours and level of font locking may be customised. See the
|
|
||||||
;; documentation on `turn-on-haskell-font-lock' for more details.
|
|
||||||
;;
|
|
||||||
;; Present Limitations/Future Work (contributions are most welcome!):
|
|
||||||
;;
|
|
||||||
;; . Debatable whether `()' `[]' `(->)' `(,)' `(,,)' etc. should be
|
|
||||||
;; highlighted as constructors or not. Should the `->' in
|
|
||||||
;; `id :: a -> a' be considered a constructor or a keyword? If so,
|
|
||||||
;; how do we distinguish this from `\x -> x'? What about the `\'?
|
|
||||||
;;
|
|
||||||
;; . XEmacs can support both `--' comments and `{- -}' comments
|
|
||||||
;; simultaneously. If XEmacs is detected, this should be used.
|
|
||||||
;;
|
|
||||||
;; . Support for GreenCard?
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; All functions/variables start with
|
|
||||||
;; `(turn-(on/off)-)haskell-font-lock' or `haskell-fl-'.
|
|
||||||
|
|
||||||
;;; Change Log:
|
|
||||||
|
|
||||||
;; Version 1.3:
|
|
||||||
;; From Dave Love:
|
|
||||||
;; Support for proper behaviour (including with Unicode identifiers)
|
|
||||||
;; in Emacs 21 only hacked in messily to avoid disturbing the old
|
|
||||||
;; stuff. Needs integrating more cleanly. Allow literate comment
|
|
||||||
;; face to be customized. Some support for fontifying definitions.
|
|
||||||
;; (I'm not convinced the faces should be customizable -- fontlock
|
|
||||||
;; faces are normally expected to be consistent.)
|
|
||||||
;;
|
|
||||||
;; Version 1.2:
|
|
||||||
;; Added support for LaTeX-style literate scripts. Allow whitespace
|
|
||||||
;; after backslash to end a line for string continuations.
|
|
||||||
;;
|
|
||||||
;; Version 1.1:
|
|
||||||
;; Use own syntax table. Use backquote (neater). Stop ''' being
|
|
||||||
;; highlighted as quoted character. Fixed `\"' fontification bug
|
|
||||||
;; in comments.
|
|
||||||
;;
|
|
||||||
;; Version 1.0:
|
|
||||||
;; Brought over from Haskell mode v1.1.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'haskell-mode)
|
|
||||||
(require 'font-lock)
|
|
||||||
|
|
||||||
(defcustom haskell-font-lock-symbols nil
|
|
||||||
"Display \\ and -> and such using symbols in fonts.
|
|
||||||
This may sound like a neat trick, but be extra careful: it changes the
|
|
||||||
alignment and can thus lead to nasty surprises w.r.t layout.
|
|
||||||
If t, try to use whichever font is available. Otherwise you can
|
|
||||||
set it to a particular font of your preference among `japanese-jisx0208'
|
|
||||||
and `unicode'."
|
|
||||||
:group 'haskell
|
|
||||||
:type '(choice (const nil)
|
|
||||||
(const t)
|
|
||||||
(const unicode)
|
|
||||||
(const japanese-jisx0208)))
|
|
||||||
|
|
||||||
(defconst haskell-font-lock-symbols-alist
|
|
||||||
(append
|
|
||||||
;; Prefer single-width Unicode font for lambda.
|
|
||||||
(and (fboundp 'decode-char)
|
|
||||||
(memq haskell-font-lock-symbols '(t unicode))
|
|
||||||
(list (cons "\\" (decode-char 'ucs 955))))
|
|
||||||
;; The symbols can come from a JIS0208 font.
|
|
||||||
(and (fboundp 'make-char) (fboundp 'charsetp) (charsetp 'japanese-jisx0208)
|
|
||||||
(memq haskell-font-lock-symbols '(t japanese-jisx0208))
|
|
||||||
(list (cons "not" (make-char 'japanese-jisx0208 34 76))
|
|
||||||
(cons "\\" (make-char 'japanese-jisx0208 38 75))
|
|
||||||
(cons "->" (make-char 'japanese-jisx0208 34 42))
|
|
||||||
(cons "<-" (make-char 'japanese-jisx0208 34 43))
|
|
||||||
(cons "=>" (make-char 'japanese-jisx0208 34 77))
|
|
||||||
;; FIXME: I'd like to either use ∀ or ∃ depending on how the
|
|
||||||
;; `forall' keyword is used, but currently the rest of the
|
|
||||||
;; code assumes that such ambiguity doesn't happen :-(
|
|
||||||
(cons "forall" (make-char 'japanese-jisx0208 34 79))))
|
|
||||||
;; Or a unicode font.
|
|
||||||
(and (fboundp 'decode-char)
|
|
||||||
(memq haskell-font-lock-symbols '(t unicode))
|
|
||||||
(list (cons "not" (decode-char 'ucs 172))
|
|
||||||
(cons "->" (decode-char 'ucs 8594))
|
|
||||||
(cons "<-" (decode-char 'ucs 8592))
|
|
||||||
(cons "=>" (decode-char 'ucs 8658))
|
|
||||||
(cons "()" (decode-char 'ucs #X2205))
|
|
||||||
(cons "==" (decode-char 'ucs #X2261))
|
|
||||||
(cons "/=" (decode-char 'ucs #X2262))
|
|
||||||
(cons ">=" (decode-char 'ucs #X2265))
|
|
||||||
(cons "<=" (decode-char 'ucs #X2264))
|
|
||||||
(cons "!!" (decode-char 'ucs #X203C))
|
|
||||||
(cons "&&" (decode-char 'ucs #X2227))
|
|
||||||
(cons "||" (decode-char 'ucs #X2228))
|
|
||||||
(cons "sqrt" (decode-char 'ucs #X221A))
|
|
||||||
(cons "undefined" (decode-char 'ucs #X22A5))
|
|
||||||
(cons "pi" (decode-char 'ucs #X3C0))
|
|
||||||
(cons "~>" (decode-char 'ucs 8669)) ;; Omega language
|
|
||||||
;; (cons "~>" (decode-char 'ucs 8605)) ;; less desirable
|
|
||||||
(cons "-<" (decode-char 'ucs 8610)) ;; Paterson's arrow syntax
|
|
||||||
;; (cons "-<" (decode-char 'ucs 10521)) ;; nicer but uncommon
|
|
||||||
(cons "::" (decode-char 'ucs 8759))
|
|
||||||
(list "." (decode-char 'ucs 8728) ; (decode-char 'ucs 9675)
|
|
||||||
;; Need a predicate here to distinguish the . used by
|
|
||||||
;; forall <foo> . <bar>.
|
|
||||||
'haskell-font-lock-dot-is-not-composition)
|
|
||||||
(cons "forall" (decode-char 'ucs 8704)))))
|
|
||||||
"Alist mapping Haskell symbols to chars.
|
|
||||||
Each element has the form (STRING . CHAR) or (STRING CHAR PREDICATE).
|
|
||||||
STRING is the Haskell symbol.
|
|
||||||
CHAR is the character with which to represent this symbol.
|
|
||||||
PREDICATE if present is a function of one argument (the start position
|
|
||||||
of the symbol) which should return non-nil if this mapping should be disabled
|
|
||||||
at that position.")
|
|
||||||
|
|
||||||
(defun haskell-font-lock-dot-is-not-composition (start)
|
|
||||||
"Return non-nil if the \".\" at START is not a composition operator.
|
|
||||||
This is the case if the \".\" is part of a \"forall <tvar> . <type>\"."
|
|
||||||
(save-excursion
|
|
||||||
(goto-char start)
|
|
||||||
(re-search-backward "\\<forall\\>[^.\"]*\\="
|
|
||||||
(line-beginning-position) t)))
|
|
||||||
|
|
||||||
(defface haskell-keyword-face
|
|
||||||
'((t :inherit font-lock-keyword-face))
|
|
||||||
"Face used to highlight Haskell keywords."
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defface haskell-constructor-face
|
|
||||||
'((t :inherit font-lock-type-face))
|
|
||||||
"Face used to highlight Haskell constructors."
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
;; This used to be `font-lock-variable-name-face' but it doesn't result in
|
|
||||||
;; a highlighting that's consistent with other modes (it's mostly used
|
|
||||||
;; for function defintions).
|
|
||||||
(defface haskell-definition-face
|
|
||||||
'((t :inherit font-lock-function-name-face))
|
|
||||||
"Face used to highlight Haskell definitions."
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
;; This is probably just wrong, but it used to use
|
|
||||||
;; `font-lock-function-name-face' with a result that was not consistent with
|
|
||||||
;; other major modes, so I just exchanged with `haskell-definition-face'.
|
|
||||||
(defface haskell-operator-face
|
|
||||||
'((t :inherit font-lock-variable-name-face))
|
|
||||||
"Face used to highlight Haskell operators."
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defface haskell-pragma-face
|
|
||||||
'((t :inherit font-lock-comment-face))
|
|
||||||
"Face used to highlight Haskell pragmas."
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defface haskell-default-face
|
|
||||||
'((t :inherit default))
|
|
||||||
"Face used to highlight ordinary Haskell code."
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defface haskell-literate-comment-face
|
|
||||||
'((t :inherit font-lock-doc-face))
|
|
||||||
"Face with which to fontify literate comments.
|
|
||||||
Inherit from `default' to avoid fontification of them."
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
;; These variables exist only for backward compatibility.
|
|
||||||
(defvar haskell-keyword-face 'haskell-keyword-face)
|
|
||||||
(defvar haskell-constructor-face 'haskell-constructor-face)
|
|
||||||
(defvar haskell-definition-face 'haskell-definition-face)
|
|
||||||
(defvar haskell-operator-face 'haskell-operator-face)
|
|
||||||
(defvar haskell-pragma-face 'haskell-pragma-face)
|
|
||||||
(defvar haskell-default-face 'haskell-default-face)
|
|
||||||
(defvar haskell-literate-comment-face 'haskell-literate-comment-face)
|
|
||||||
|
|
||||||
(defun haskell-font-lock-compose-symbol (alist)
|
|
||||||
"Compose a sequence of ascii chars into a symbol.
|
|
||||||
Regexp match data 0 points to the chars."
|
|
||||||
;; Check that the chars should really be composed into a symbol.
|
|
||||||
(let* ((start (match-beginning 0))
|
|
||||||
(end (match-end 0))
|
|
||||||
(syntaxes (cond
|
|
||||||
((eq (char-syntax (char-after start)) ?w) '(?w))
|
|
||||||
;; Special case for the . used for qualified names.
|
|
||||||
((and (eq (char-after start) ?\.) (= end (1+ start)))
|
|
||||||
'(?_ ?\\ ?w))
|
|
||||||
(t '(?_ ?\\))))
|
|
||||||
sym-data)
|
|
||||||
(if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes)
|
|
||||||
(memq (char-syntax (or (char-after end) ?\ )) syntaxes)
|
|
||||||
(or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4))
|
|
||||||
(and (consp (setq sym-data (cdr (assoc (match-string 0) alist))))
|
|
||||||
(let ((pred (cadr sym-data)))
|
|
||||||
(setq sym-data (car sym-data))
|
|
||||||
(funcall pred start))))
|
|
||||||
;; No composition for you. Let's actually remove any composition
|
|
||||||
;; we may have added earlier and which is now incorrect.
|
|
||||||
(remove-text-properties start end '(composition))
|
|
||||||
;; That's a symbol alright, so add the composition.
|
|
||||||
(compose-region start end sym-data)))
|
|
||||||
;; Return nil because we're not adding any face property.
|
|
||||||
nil)
|
|
||||||
|
|
||||||
(defun haskell-font-lock-symbols-keywords ()
|
|
||||||
(when (fboundp 'compose-region)
|
|
||||||
(let ((alist nil))
|
|
||||||
(dolist (x haskell-font-lock-symbols-alist)
|
|
||||||
(when (and (if (fboundp 'char-displayable-p)
|
|
||||||
(char-displayable-p (if (consp (cdr x)) (cadr x) (cdr x)))
|
|
||||||
(if (fboundp 'latin1-char-displayable-p)
|
|
||||||
(latin1-char-displayable-p (if (consp (cdr x))
|
|
||||||
(cadr x)
|
|
||||||
(cdr x)))
|
|
||||||
t))
|
|
||||||
(not (assoc (car x) alist))) ; Not yet in alist.
|
|
||||||
(push x alist)))
|
|
||||||
(when alist
|
|
||||||
`((,(regexp-opt (mapcar 'car alist) t)
|
|
||||||
(0 (haskell-font-lock-compose-symbol ',alist)
|
|
||||||
;; In Emacs-21, if the `override' field is nil, the face
|
|
||||||
;; expressions is only evaluated if the text has currently
|
|
||||||
;; no face. So force evaluation by using `keep'.
|
|
||||||
keep)))))))
|
|
||||||
|
|
||||||
(defun haskell-font-lock-find-pragma (end)
|
|
||||||
(catch 'haskell-font-lock-find-pragma
|
|
||||||
(while (search-forward "{-#" end t)
|
|
||||||
(let* ((begin (match-beginning 0))
|
|
||||||
(ppss (save-excursion (syntax-ppss begin))))
|
|
||||||
;; We're interested only when it's not in a string or a comment.
|
|
||||||
(unless (or (nth 3 ppss)
|
|
||||||
(nth 4 ppss))
|
|
||||||
;; Find the end of the pragma.
|
|
||||||
(let ((end (scan-lists begin 1 0)))
|
|
||||||
;; Match data contains only the opening {-#, update it to cover the
|
|
||||||
;; whole pragma.
|
|
||||||
(set-match-data (list begin end))
|
|
||||||
;; Move to the end so we don't start the next scan from inside the
|
|
||||||
;; pragma we just found.
|
|
||||||
(goto-char end)
|
|
||||||
(throw 'haskell-font-lock-find-pragma t)))))
|
|
||||||
;; Found no pragma.
|
|
||||||
nil))
|
|
||||||
|
|
||||||
;; The font lock regular expressions.
|
|
||||||
(defun haskell-font-lock-keywords-create (literate)
|
|
||||||
"Create fontification definitions for Haskell scripts.
|
|
||||||
Returns keywords suitable for `font-lock-keywords'."
|
|
||||||
(let* (;; Bird-style literate scripts start a line of code with
|
|
||||||
;; "^>", otherwise a line of code starts with "^".
|
|
||||||
(line-prefix (if (eq literate 'bird) "^> ?" "^"))
|
|
||||||
|
|
||||||
;; Most names are borrowed from the lexical syntax of the Haskell
|
|
||||||
;; report.
|
|
||||||
;; Some of these definitions have been superseded by using the
|
|
||||||
;; syntax table instead.
|
|
||||||
|
|
||||||
;; (ASCsymbol "-!#$%&*+./<=>?@\\\\^|~")
|
|
||||||
;; Put the minus first to make it work in ranges.
|
|
||||||
|
|
||||||
;; We allow _ as the first char to fit GHC
|
|
||||||
(varid "\\b[[:lower:]_][[:alnum:]'_]*\\b")
|
|
||||||
;; We allow ' preceding conids because of DataKinds/PolyKinds
|
|
||||||
(conid "\\b'?[[:upper:]][[:alnum:]'_]*\\b")
|
|
||||||
(modid (concat "\\b" conid "\\(\\." conid "\\)*\\b"))
|
|
||||||
(qvarid (concat modid "\\." varid))
|
|
||||||
(qconid (concat modid "\\." conid))
|
|
||||||
(sym
|
|
||||||
;; We used to use the below for non-Emacs21, but I think the
|
|
||||||
;; regexp based on syntax works for other emacsen as well. -- Stef
|
|
||||||
;; (concat "[" symbol ":]+")
|
|
||||||
;; Add backslash to the symbol-syntax chars. This seems to
|
|
||||||
;; be thrown for some reason by backslash's escape syntax.
|
|
||||||
"\\(\\s_\\|\\\\\\)+")
|
|
||||||
|
|
||||||
;; Reserved operations
|
|
||||||
(reservedsym
|
|
||||||
(concat "\\S."
|
|
||||||
;; (regexp-opt '(".." "::" "=" "\\" "|" "<-" "->"
|
|
||||||
;; "@" "~" "=>") t)
|
|
||||||
"\\(->\\|→\\|\\.\\.\\|::\\|∷\\|<-\\|←\\|=>\\|[=@\\|~]\\)"
|
|
||||||
"\\S."))
|
|
||||||
;; Reserved identifiers
|
|
||||||
(reservedid
|
|
||||||
(concat "\\<"
|
|
||||||
;; `as', `hiding', and `qualified' are part of the import
|
|
||||||
;; spec syntax, but they are not reserved.
|
|
||||||
;; `_' can go in here since it has temporary word syntax.
|
|
||||||
;; (regexp-opt
|
|
||||||
;; '("case" "class" "data" "default" "deriving" "do"
|
|
||||||
;; "else" "if" "import" "in" "infix" "infixl"
|
|
||||||
;; "infixr" "instance" "let" "module" "newtype" "of"
|
|
||||||
;; "then" "type" "where" "_") t)
|
|
||||||
"\\(_\\|c\\(ase\\|lass\\)\\|d\\(ata\\|e\\(fault\\|riving\\)\\|o\\)\\|else\\|i\\(mport\\|n\\(fix[lr]?\\|stance\\)\\|[fn]\\)\\|let\\|module\\|mdo\\|newtype\\|of\\|rec\\|proc\\|t\\(hen\\|ype\\)\\|where\\)"
|
|
||||||
"\\>"))
|
|
||||||
|
|
||||||
;; This unreadable regexp matches strings and character
|
|
||||||
;; constants. We need to do this with one regexp to handle
|
|
||||||
;; stuff like '"':"'". The regexp is the composition of
|
|
||||||
;; "([^"\\]|\\.)*" for strings and '([^\\]|\\.[^']*)' for
|
|
||||||
;; characters, allowing for string continuations.
|
|
||||||
;; Could probably be improved...
|
|
||||||
(string-and-char
|
|
||||||
(concat "\\(\\(\"\\|" line-prefix "[ \t]*\\\\\\)\\([^\"\\\\\n]\\|\\\\.\\)*\\(\"\\|\\\\[ \t]*$\\)\\|'\\([^'\\\\\n]\\|\\\\.[^'\n]*\\)'\\)"))
|
|
||||||
|
|
||||||
;; Top-level declarations
|
|
||||||
(topdecl-var
|
|
||||||
(concat line-prefix "\\(" varid "\\(?:\\s-*,\\s-*" varid "\\)*" "\\)\\s-*"
|
|
||||||
;; optionally allow for a single newline after identifier
|
|
||||||
;; NOTE: not supported for bird-style .lhs files
|
|
||||||
(if (eq literate 'bird) nil "\\([\n]\\s-+\\)?")
|
|
||||||
;; A toplevel declaration can be followed by a definition
|
|
||||||
;; (=), a type (::) or (∷), a guard, or a pattern which can
|
|
||||||
;; either be a variable, a constructor, a parenthesized
|
|
||||||
;; thingy, or an integer or a string.
|
|
||||||
"\\(" varid "\\|" conid "\\|::\\|∷\\|=\\||\\|\\s(\\|[0-9\"']\\)"))
|
|
||||||
(topdecl-var2
|
|
||||||
(concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*`\\(" varid "\\)`"))
|
|
||||||
(topdecl-bangpat
|
|
||||||
(concat line-prefix "\\(" varid "\\)\\s-*!"))
|
|
||||||
(topdecl-sym
|
|
||||||
(concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*\\(" sym "\\)"))
|
|
||||||
(topdecl-sym2 (concat line-prefix "(\\(" sym "\\))"))
|
|
||||||
|
|
||||||
keywords)
|
|
||||||
|
|
||||||
(setq keywords
|
|
||||||
`(;; NOTICE the ordering below is significant
|
|
||||||
;;
|
|
||||||
("^<<<<<<< .*$" 0 'font-lock-warning-face t)
|
|
||||||
("^|||||||$" 0 'font-lock-warning-face t) ; "diff3" style
|
|
||||||
("^=======$" 0 'font-lock-warning-face t)
|
|
||||||
("^>>>>>>> .*$" 0 'font-lock-warning-face t)
|
|
||||||
("^#.*$" 0 'font-lock-preprocessor-face t)
|
|
||||||
|
|
||||||
,@(haskell-font-lock-symbols-keywords)
|
|
||||||
|
|
||||||
(,reservedid 1 haskell-keyword-face)
|
|
||||||
(,reservedsym 1 haskell-operator-face)
|
|
||||||
;; Special case for `as', `hiding', `safe' and `qualified', which are
|
|
||||||
;; keywords in import statements but are not otherwise reserved.
|
|
||||||
("\\<import[ \t]+\\(?:\\(safe\\>\\)[ \t]*\\)?\\(?:\\(qualified\\>\\)[ \t]*\\)?\\(?:\"[^\"]*\"[\t ]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\<as\\>\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\<hiding\\>\\)?"
|
|
||||||
(1 haskell-keyword-face nil lax)
|
|
||||||
(2 haskell-keyword-face nil lax)
|
|
||||||
(3 haskell-keyword-face nil lax)
|
|
||||||
(4 haskell-keyword-face nil lax))
|
|
||||||
|
|
||||||
(,reservedsym 1 haskell-operator-face)
|
|
||||||
;; Special case for `foreign import'
|
|
||||||
;; keywords in foreign import statements but are not otherwise reserved.
|
|
||||||
("\\<\\(foreign\\)[ \t]+\\(import\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?\\(?:\\(safe\\|unsafe\\|interruptible\\)[ \t]+\\)?"
|
|
||||||
(1 haskell-keyword-face nil lax)
|
|
||||||
(2 haskell-keyword-face nil lax)
|
|
||||||
(3 haskell-keyword-face nil lax)
|
|
||||||
(4 haskell-keyword-face nil lax))
|
|
||||||
|
|
||||||
(,reservedsym 1 haskell-operator-face)
|
|
||||||
;; Special case for `foreign export'
|
|
||||||
;; keywords in foreign export statements but are not otherwise reserved.
|
|
||||||
("\\<\\(foreign\\)[ \t]+\\(export\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?"
|
|
||||||
(1 haskell-keyword-face nil lax)
|
|
||||||
(2 haskell-keyword-face nil lax)
|
|
||||||
(3 haskell-keyword-face nil lax))
|
|
||||||
|
|
||||||
;; Toplevel Declarations.
|
|
||||||
;; Place them *before* generic id-and-op highlighting.
|
|
||||||
(,topdecl-var (1 haskell-definition-face))
|
|
||||||
(,topdecl-var2 (2 haskell-definition-face))
|
|
||||||
(,topdecl-bangpat (1 haskell-definition-face))
|
|
||||||
(,topdecl-sym (2 haskell-definition-face))
|
|
||||||
(,topdecl-sym2 (1 haskell-definition-face))
|
|
||||||
|
|
||||||
;; These four are debatable...
|
|
||||||
("(\\(,*\\|->\\))" 0 haskell-constructor-face)
|
|
||||||
("\\[\\]" 0 haskell-constructor-face)
|
|
||||||
;; Expensive.
|
|
||||||
(,(concat "`" varid "`") 0 haskell-operator-face)
|
|
||||||
(,(concat "`" conid "`") 0 haskell-operator-face)
|
|
||||||
(,(concat "`" qvarid "`") 0 haskell-operator-face)
|
|
||||||
(,(concat "`" qconid "`") 0 haskell-operator-face)
|
|
||||||
(,qvarid 0 haskell-default-face)
|
|
||||||
(,qconid 0 haskell-constructor-face)
|
|
||||||
;; Expensive.
|
|
||||||
(,conid 0 haskell-constructor-face)
|
|
||||||
|
|
||||||
;; Very expensive.
|
|
||||||
(,sym 0 (if (eq (char-after (match-beginning 0)) ?:)
|
|
||||||
haskell-constructor-face
|
|
||||||
haskell-operator-face))
|
|
||||||
|
|
||||||
(haskell-font-lock-find-pragma 0 haskell-pragma-face t)))
|
|
||||||
(unless (boundp 'font-lock-syntactic-keywords)
|
|
||||||
(cl-case literate
|
|
||||||
(bird
|
|
||||||
(setq keywords
|
|
||||||
`(("^[^>\n].*$" 0 haskell-comment-face t)
|
|
||||||
,@keywords
|
|
||||||
("^>" 0 haskell-default-face t))))
|
|
||||||
((latex tex)
|
|
||||||
(setq keywords
|
|
||||||
`((haskell-font-lock-latex-comments 0 'font-lock-comment-face t)
|
|
||||||
,@keywords)))))
|
|
||||||
keywords))
|
|
||||||
|
|
||||||
(defvar haskell-font-lock-latex-cache-pos nil
|
|
||||||
"Position of cache point used by `haskell-font-lock-latex-cache-in-comment'.
|
|
||||||
Should be at the start of a line.")
|
|
||||||
(make-variable-buffer-local 'haskell-font-lock-latex-cache-pos)
|
|
||||||
|
|
||||||
(defvar haskell-font-lock-latex-cache-in-comment nil
|
|
||||||
"If `haskell-font-lock-latex-cache-pos' is outside a
|
|
||||||
\\begin{code}..\\end{code} block (and therefore inside a comment),
|
|
||||||
this variable is set to t, otherwise nil.")
|
|
||||||
(make-variable-buffer-local 'haskell-font-lock-latex-cache-in-comment)
|
|
||||||
|
|
||||||
(defun haskell-font-lock-latex-comments (end)
|
|
||||||
"Sets `match-data' according to the region of the buffer before end
|
|
||||||
that should be commented under LaTeX-style literate scripts."
|
|
||||||
(let ((start (point)))
|
|
||||||
(if (= start end)
|
|
||||||
;; We're at the end. No more to fontify.
|
|
||||||
nil
|
|
||||||
(if (not (eq start haskell-font-lock-latex-cache-pos))
|
|
||||||
;; If the start position is not cached, calculate the state
|
|
||||||
;; of the start.
|
|
||||||
(progn
|
|
||||||
(setq haskell-font-lock-latex-cache-pos start)
|
|
||||||
;; If the previous \begin{code} or \end{code} is a
|
|
||||||
;; \begin{code}, then start is not in a comment, otherwise
|
|
||||||
;; it is in a comment.
|
|
||||||
(setq haskell-font-lock-latex-cache-in-comment
|
|
||||||
(if (and
|
|
||||||
(re-search-backward
|
|
||||||
"^\\(\\(\\\\begin{code}\\)\\|\\(\\\\end{code}\\)\\)$"
|
|
||||||
(point-min) t)
|
|
||||||
(match-end 2))
|
|
||||||
nil t))
|
|
||||||
;; Restore position.
|
|
||||||
(goto-char start)))
|
|
||||||
(if haskell-font-lock-latex-cache-in-comment
|
|
||||||
(progn
|
|
||||||
;; If start is inside a comment, search for next \begin{code}.
|
|
||||||
(re-search-forward "^\\\\begin{code}$" end 'move)
|
|
||||||
;; Mark start to end of \begin{code} (if present, till end
|
|
||||||
;; otherwise), as a comment.
|
|
||||||
(set-match-data (list start (point)))
|
|
||||||
;; Return point, as a normal regexp would.
|
|
||||||
(point))
|
|
||||||
;; If start is inside a code block, search for next \end{code}.
|
|
||||||
(if (re-search-forward "^\\\\end{code}$" end t)
|
|
||||||
;; If one found, mark it as a comment, otherwise finish.
|
|
||||||
(point))))))
|
|
||||||
|
|
||||||
(defconst haskell-basic-syntactic-keywords
|
|
||||||
'(;; Character constants (since apostrophe can't have string syntax).
|
|
||||||
;; Beware: do not match something like 's-}' or '\n"+' since the first '
|
|
||||||
;; might be inside a comment or a string.
|
|
||||||
;; This still gets fooled with "'"'"'"'"'"', but ... oh well.
|
|
||||||
("\\Sw\\('\\)\\([^\\'\n]\\|\\\\.[^\\'\n \"}]*\\)\\('\\)" (1 "|") (3 "|"))
|
|
||||||
;; The \ is not escaping in \(x,y) -> x + y.
|
|
||||||
("\\(\\\\\\)(" (1 "."))
|
|
||||||
;; The second \ in a gap does not quote the subsequent char.
|
|
||||||
;; It's probably not worth the trouble, tho.
|
|
||||||
;; ("^[ \t]*\\(\\\\\\)" (1 "."))
|
|
||||||
;; Deal with instances of `--' which don't form a comment
|
|
||||||
("\\s_\\{3,\\}" (0 (cond ((numberp (nth 4 (syntax-ppss)))
|
|
||||||
;; There are no such instances inside nestable comments
|
|
||||||
nil)
|
|
||||||
((string-match "\\`-*\\'" (match-string 0))
|
|
||||||
;; Sequence of hyphens. Do nothing in
|
|
||||||
;; case of things like `{---'.
|
|
||||||
nil)
|
|
||||||
(t "_")))) ; other symbol sequence
|
|
||||||
))
|
|
||||||
|
|
||||||
(defconst haskell-bird-syntactic-keywords
|
|
||||||
(cons '("^[^\n>]" (0 "<"))
|
|
||||||
haskell-basic-syntactic-keywords))
|
|
||||||
|
|
||||||
(defconst haskell-latex-syntactic-keywords
|
|
||||||
(append
|
|
||||||
'(("^\\\\begin{code}\\(\n\\)" 1 "!")
|
|
||||||
;; Note: buffer is widened during font-locking.
|
|
||||||
("\\`\\(.\\|\n\\)" (1 "!")) ; start comment at buffer start
|
|
||||||
("^\\(\\\\\\)end{code}$" 1 "!"))
|
|
||||||
haskell-basic-syntactic-keywords))
|
|
||||||
|
|
||||||
(defcustom haskell-font-lock-haddock (boundp 'font-lock-doc-face)
|
|
||||||
"If non-nil try to highlight Haddock comments specially."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'haskell)
|
|
||||||
|
|
||||||
(defvar haskell-font-lock-seen-haddock nil)
|
|
||||||
(make-variable-buffer-local 'haskell-font-lock-seen-haddock)
|
|
||||||
|
|
||||||
(defun haskell-syntactic-face-function (state)
|
|
||||||
"`font-lock-syntactic-face-function' for Haskell."
|
|
||||||
(cond
|
|
||||||
((nth 3 state) font-lock-string-face) ; as normal
|
|
||||||
;; Else comment. If it's from syntax table, use default face.
|
|
||||||
((or (eq 'syntax-table (nth 7 state))
|
|
||||||
(and (eq haskell-literate 'bird)
|
|
||||||
(memq (char-before (nth 8 state)) '(nil ?\n))))
|
|
||||||
haskell-literate-comment-face)
|
|
||||||
;; Try and recognize Haddock comments. From what I gather from its
|
|
||||||
;; documentation, its comments can take the following forms:
|
|
||||||
;; a) {-| ... -}
|
|
||||||
;; b) {-^ ... -}
|
|
||||||
;; c) -- | ...
|
|
||||||
;; d) -- ^ ...
|
|
||||||
;; e) -- ...
|
|
||||||
;; Where `e' is the tricky one: it is only a Haddock comment if it
|
|
||||||
;; follows immediately another Haddock comment. Even an empty line
|
|
||||||
;; breaks such a sequence of Haddock comments. It is not clear if `e'
|
|
||||||
;; can follow any other case, so I interpreted it as following only cases
|
|
||||||
;; c,d,e (not a or b). In any case, this `e' is expensive since it
|
|
||||||
;; requires extra work for each and every non-Haddock comment, so I only
|
|
||||||
;; go through the more expensive check if we've already seen a Haddock
|
|
||||||
;; comment in the buffer.
|
|
||||||
;;
|
|
||||||
;; And then there are also haddock section headers that start with
|
|
||||||
;; any number of stars:
|
|
||||||
;; -- * ...
|
|
||||||
((and haskell-font-lock-haddock
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (nth 8 state))
|
|
||||||
(or (looking-at "\\(?:{- ?\\|-- \\)[|^*$]")
|
|
||||||
(and haskell-font-lock-seen-haddock
|
|
||||||
(looking-at "--")
|
|
||||||
(let ((doc nil)
|
|
||||||
pos)
|
|
||||||
(while (and (not doc)
|
|
||||||
(setq pos (line-beginning-position))
|
|
||||||
(forward-comment -1)
|
|
||||||
(eq (line-beginning-position 2) pos)
|
|
||||||
(looking-at "--\\([ \\t]*[|^*]\\)?"))
|
|
||||||
(setq doc (match-beginning 1)))
|
|
||||||
doc)))))
|
|
||||||
(setq haskell-font-lock-seen-haddock t)
|
|
||||||
font-lock-doc-face)
|
|
||||||
(t font-lock-comment-face)))
|
|
||||||
|
|
||||||
(defconst haskell-font-lock-keywords
|
|
||||||
(haskell-font-lock-keywords-create nil)
|
|
||||||
"Font lock definitions for non-literate Haskell.")
|
|
||||||
|
|
||||||
(defconst haskell-font-lock-bird-literate-keywords
|
|
||||||
(haskell-font-lock-keywords-create 'bird)
|
|
||||||
"Font lock definitions for Bird-style literate Haskell.")
|
|
||||||
|
|
||||||
(defconst haskell-font-lock-latex-literate-keywords
|
|
||||||
(haskell-font-lock-keywords-create 'latex)
|
|
||||||
"Font lock definitions for LaTeX-style literate Haskell.")
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-font-lock-choose-keywords ()
|
|
||||||
(let ((literate (if (boundp 'haskell-literate) haskell-literate)))
|
|
||||||
(cl-case literate
|
|
||||||
(bird haskell-font-lock-bird-literate-keywords)
|
|
||||||
((latex tex) haskell-font-lock-latex-literate-keywords)
|
|
||||||
(t haskell-font-lock-keywords))))
|
|
||||||
|
|
||||||
(defun haskell-font-lock-choose-syntactic-keywords ()
|
|
||||||
(let ((literate (if (boundp 'haskell-literate) haskell-literate)))
|
|
||||||
(cl-case literate
|
|
||||||
(bird haskell-bird-syntactic-keywords)
|
|
||||||
((latex tex) haskell-latex-syntactic-keywords)
|
|
||||||
(t haskell-basic-syntactic-keywords))))
|
|
||||||
|
|
||||||
(defun haskell-font-lock-defaults-create ()
|
|
||||||
"Locally set `font-lock-defaults' for Haskell."
|
|
||||||
(set (make-local-variable 'font-lock-defaults)
|
|
||||||
'(haskell-font-lock-choose-keywords
|
|
||||||
nil nil ((?\' . "w") (?_ . "w")) nil
|
|
||||||
(font-lock-syntactic-keywords
|
|
||||||
. haskell-font-lock-choose-syntactic-keywords)
|
|
||||||
(font-lock-syntactic-face-function
|
|
||||||
. haskell-syntactic-face-function)
|
|
||||||
;; Get help from font-lock-syntactic-keywords.
|
|
||||||
(parse-sexp-lookup-properties . t))))
|
|
||||||
|
|
||||||
;; The main functions.
|
|
||||||
(defun turn-on-haskell-font-lock ()
|
|
||||||
"Turns on font locking in current buffer for Haskell 1.4 scripts.
|
|
||||||
|
|
||||||
Changes the current buffer's `font-lock-defaults', and adds the
|
|
||||||
following variables:
|
|
||||||
|
|
||||||
`haskell-keyword-face' for reserved keywords and syntax,
|
|
||||||
`haskell-constructor-face' for data- and type-constructors, class names,
|
|
||||||
and module names,
|
|
||||||
`haskell-operator-face' for symbolic and alphanumeric operators,
|
|
||||||
`haskell-default-face' for ordinary code.
|
|
||||||
|
|
||||||
The variables are initialised to the following font lock default faces:
|
|
||||||
|
|
||||||
`haskell-keyword-face' `font-lock-keyword-face'
|
|
||||||
`haskell-constructor-face' `font-lock-type-face'
|
|
||||||
`haskell-operator-face' `font-lock-function-name-face'
|
|
||||||
`haskell-default-face' <default face>
|
|
||||||
|
|
||||||
Two levels of fontification are defined: level one (the default)
|
|
||||||
and level two (more colour). The former does not colour operators.
|
|
||||||
Use the variable `font-lock-maximum-decoration' to choose
|
|
||||||
non-default levels of fontification. For example, adding this to
|
|
||||||
.emacs:
|
|
||||||
|
|
||||||
(setq font-lock-maximum-decoration '((haskell-mode . 2) (t . 0)))
|
|
||||||
|
|
||||||
uses level two fontification for `haskell-mode' and default level for
|
|
||||||
all other modes. See documentation on this variable for further
|
|
||||||
details.
|
|
||||||
|
|
||||||
To alter an attribute of a face, add a hook. For example, to change
|
|
||||||
the foreground colour of comments to brown, add the following line to
|
|
||||||
.emacs:
|
|
||||||
|
|
||||||
(add-hook 'haskell-font-lock-hook
|
|
||||||
(lambda ()
|
|
||||||
(set-face-foreground 'haskell-comment-face \"brown\")))
|
|
||||||
|
|
||||||
Note that the colours available vary from system to system. To see
|
|
||||||
what colours are available on your system, call
|
|
||||||
`list-colors-display' from emacs.
|
|
||||||
|
|
||||||
To turn font locking on for all Haskell buffers, add this to .emacs:
|
|
||||||
|
|
||||||
(add-hook 'haskell-mode-hook 'turn-on-haskell-font-lock)
|
|
||||||
|
|
||||||
To turn font locking on for the current buffer, call
|
|
||||||
`turn-on-haskell-font-lock'. To turn font locking off in the current
|
|
||||||
buffer, call `turn-off-haskell-font-lock'.
|
|
||||||
|
|
||||||
Bird-style literate Haskell scripts are supported: If the value of
|
|
||||||
`haskell-literate-bird-style' (automatically set by the Haskell mode
|
|
||||||
of Moss&Thorn) is non-nil, a Bird-style literate script is assumed.
|
|
||||||
|
|
||||||
Invokes `haskell-font-lock-hook' if not nil."
|
|
||||||
(haskell-font-lock-defaults-create)
|
|
||||||
(run-hooks 'haskell-font-lock-hook)
|
|
||||||
(turn-on-font-lock))
|
|
||||||
|
|
||||||
(defun turn-off-haskell-font-lock ()
|
|
||||||
"Turns off font locking in current buffer."
|
|
||||||
(font-lock-mode -1))
|
|
||||||
|
|
||||||
(defun haskell-fontify-as-mode (text mode)
|
|
||||||
"Fontify TEXT as MODE, returning the fontified text."
|
|
||||||
(with-temp-buffer
|
|
||||||
(funcall mode)
|
|
||||||
(insert text)
|
|
||||||
(if (fboundp 'font-lock-ensure)
|
|
||||||
(font-lock-ensure)
|
|
||||||
(with-no-warnings (font-lock-fontify-buffer)))
|
|
||||||
(buffer-substring (point-min) (point-max))))
|
|
||||||
|
|
||||||
;; Provide ourselves:
|
|
||||||
|
|
||||||
(provide 'haskell-font-lock)
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; tab-width: 8
|
|
||||||
;; End:
|
|
||||||
|
|
||||||
;;; haskell-font-lock.el ends here
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,398 +0,0 @@
|
|||||||
;;; haskell-load.el --- Compiling and loading modules in the GHCi process
|
|
||||||
|
|
||||||
;; Copyright (c) 2014 Chris Done. All rights reserved.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'haskell-process)
|
|
||||||
(require 'haskell-interactive-mode)
|
|
||||||
(require 'haskell-modules)
|
|
||||||
(require 'haskell-commands)
|
|
||||||
(require 'haskell-session)
|
|
||||||
|
|
||||||
(defun haskell-process-look-config-changes (session)
|
|
||||||
"Checks whether a cabal configuration file has
|
|
||||||
changed. Restarts the process if that is the case."
|
|
||||||
(let ((current-checksum (haskell-session-get session 'cabal-checksum))
|
|
||||||
(new-checksum (haskell-cabal-compute-checksum
|
|
||||||
(haskell-session-get session 'cabal-dir))))
|
|
||||||
(when (not (string= current-checksum new-checksum))
|
|
||||||
(haskell-interactive-mode-echo session (format "Cabal file changed: %s" new-checksum))
|
|
||||||
(haskell-session-set-cabal-checksum session
|
|
||||||
(haskell-session-get session 'cabal-dir))
|
|
||||||
(unless (and haskell-process-prompt-restart-on-cabal-change
|
|
||||||
(not (y-or-n-p "Cabal file changed; restart GHCi process? ")))
|
|
||||||
(haskell-process-start (haskell-interactive-session))))))
|
|
||||||
|
|
||||||
(defun haskell-process-live-build (process buffer echo-in-repl)
|
|
||||||
"Show live updates for loading files."
|
|
||||||
(cond ((haskell-process-consume
|
|
||||||
process
|
|
||||||
(concat "\\[[ ]*\\([0-9]+\\) of \\([0-9]+\\)\\]"
|
|
||||||
" Compiling \\([^ ]+\\)[ ]+"
|
|
||||||
"( \\([^ ]+\\), \\([^ ]+\\) )[^\r\n]*[\r\n]+"))
|
|
||||||
(haskell-process-echo-load-message process buffer echo-in-repl nil)
|
|
||||||
t)
|
|
||||||
((haskell-process-consume
|
|
||||||
process
|
|
||||||
(concat "\\[[ ]*\\([0-9]+\\) of \\([0-9]+\\)\\]"
|
|
||||||
" Compiling \\[TH\\] \\([^ ]+\\)[ ]+"
|
|
||||||
"( \\([^ ]+\\), \\([^ ]+\\) )[^\r\n]*[\r\n]+"))
|
|
||||||
(haskell-process-echo-load-message process buffer echo-in-repl t)
|
|
||||||
t)
|
|
||||||
((haskell-process-consume process "Loading package \\([^ ]+\\) ... linking ... done.\n")
|
|
||||||
(haskell-mode-message-line
|
|
||||||
(format "Loading: %s"
|
|
||||||
(match-string 1 buffer)))
|
|
||||||
t)
|
|
||||||
((haskell-process-consume
|
|
||||||
process
|
|
||||||
"^Preprocessing executables for \\(.+?\\)\\.\\.\\.")
|
|
||||||
(let ((msg (format "Preprocessing: %s" (match-string 1 buffer))))
|
|
||||||
(haskell-interactive-mode-echo
|
|
||||||
(haskell-process-session process)
|
|
||||||
msg)
|
|
||||||
(haskell-mode-message-line msg)))
|
|
||||||
((haskell-process-consume process "Linking \\(.+?\\) \\.\\.\\.")
|
|
||||||
(let ((msg (format "Linking: %s" (match-string 1 buffer))))
|
|
||||||
(haskell-interactive-mode-echo (haskell-process-session process) msg)
|
|
||||||
(haskell-mode-message-line msg)))
|
|
||||||
((haskell-process-consume process "\nBuilding \\(.+?\\)\\.\\.\\.")
|
|
||||||
(let ((msg (format "Building: %s" (match-string 1 buffer))))
|
|
||||||
(haskell-interactive-mode-echo
|
|
||||||
(haskell-process-session process)
|
|
||||||
msg)
|
|
||||||
(haskell-mode-message-line msg)))))
|
|
||||||
|
|
||||||
(defun haskell-process-load-complete (session process buffer reload module-buffer &optional cont)
|
|
||||||
"Handle the complete loading response. BUFFER is the string of
|
|
||||||
text being sent over the process pipe. MODULE-BUFFER is the
|
|
||||||
actual Emacs buffer of the module being loaded."
|
|
||||||
(when (get-buffer (format "*%s:splices*" (haskell-session-name session)))
|
|
||||||
(with-current-buffer (haskell-interactive-mode-splices-buffer session)
|
|
||||||
(erase-buffer)))
|
|
||||||
(cond ((haskell-process-consume process "Ok, modules loaded: \\(.+\\)\\.$")
|
|
||||||
(let* ((modules (haskell-process-extract-modules buffer))
|
|
||||||
(cursor (haskell-process-response-cursor process)))
|
|
||||||
(haskell-process-set-response-cursor process 0)
|
|
||||||
(let ((warning-count 0))
|
|
||||||
(while (haskell-process-errors-warnings session process buffer)
|
|
||||||
(setq warning-count (1+ warning-count)))
|
|
||||||
(haskell-process-set-response-cursor process cursor)
|
|
||||||
(if (and (not reload)
|
|
||||||
haskell-process-reload-with-fbytecode)
|
|
||||||
(haskell-process-reload-with-fbytecode process module-buffer)
|
|
||||||
(haskell-process-import-modules process (car modules)))
|
|
||||||
(haskell-mode-message-line
|
|
||||||
(if reload "Reloaded OK." "OK."))
|
|
||||||
(when cont
|
|
||||||
(condition-case e
|
|
||||||
(funcall cont t)
|
|
||||||
(error (message "%S" e))
|
|
||||||
(quit nil))))))
|
|
||||||
((haskell-process-consume process "Failed, modules loaded: \\(.+\\)\\.$")
|
|
||||||
(let* ((modules (haskell-process-extract-modules buffer))
|
|
||||||
(cursor (haskell-process-response-cursor process)))
|
|
||||||
(haskell-process-set-response-cursor process 0)
|
|
||||||
(while (haskell-process-errors-warnings session process buffer))
|
|
||||||
(haskell-process-set-response-cursor process cursor)
|
|
||||||
(if (and (not reload) haskell-process-reload-with-fbytecode)
|
|
||||||
(haskell-process-reload-with-fbytecode process module-buffer)
|
|
||||||
(haskell-process-import-modules process (car modules)))
|
|
||||||
(haskell-interactive-mode-compile-error session "Compilation failed.")
|
|
||||||
(when cont
|
|
||||||
(condition-case e
|
|
||||||
(funcall cont nil)
|
|
||||||
(error (message "%S" e))
|
|
||||||
(quit nil)))))))
|
|
||||||
|
|
||||||
(defun haskell-process-suggest-imports (session file modules ident)
|
|
||||||
"Given a list of MODULES, suggest adding them to the import section."
|
|
||||||
(cl-assert session)
|
|
||||||
(cl-assert file)
|
|
||||||
(cl-assert ident)
|
|
||||||
(let* ((process (haskell-session-process session))
|
|
||||||
(suggested-already (haskell-process-suggested-imports process))
|
|
||||||
(module (cond ((> (length modules) 1)
|
|
||||||
(when (y-or-n-p (format "Identifier `%s' not in scope, choose module to import?"
|
|
||||||
ident))
|
|
||||||
(haskell-complete-module-read "Module: " modules)))
|
|
||||||
((= (length modules) 1)
|
|
||||||
(let ((module (car modules)))
|
|
||||||
(unless (member module suggested-already)
|
|
||||||
(haskell-process-set-suggested-imports process (cons module suggested-already))
|
|
||||||
(when (y-or-n-p (format "Identifier `%s' not in scope, import `%s'?"
|
|
||||||
ident
|
|
||||||
module))
|
|
||||||
module)))))))
|
|
||||||
(when module
|
|
||||||
(haskell-process-find-file session file)
|
|
||||||
(haskell-add-import module))))
|
|
||||||
|
|
||||||
(defun haskell-process-trigger-suggestions (session msg file line)
|
|
||||||
"Trigger prompting to add any extension suggestions."
|
|
||||||
(cond ((let ((case-fold-search nil))
|
|
||||||
(or (and (string-match " -X\\([A-Z][A-Za-z]+\\)" msg)
|
|
||||||
(not (string-match "\\([A-Z][A-Za-z]+\\) is deprecated" msg)))
|
|
||||||
(string-match "Use \\([A-Z][A-Za-z]+\\) to permit this" msg)
|
|
||||||
(string-match "Use \\([A-Z][A-Za-z]+\\) to allow" msg)
|
|
||||||
(string-match "use \\([A-Z][A-Za-z]+\\)" msg)
|
|
||||||
(string-match "You need \\([A-Z][A-Za-z]+\\)" msg)))
|
|
||||||
(when haskell-process-suggest-language-pragmas
|
|
||||||
(haskell-process-suggest-pragma session "LANGUAGE" (match-string 1 msg) file)))
|
|
||||||
((string-match " The \\(qualified \\)?import of[ ][‘`‛]\\([^ ]+\\)['’] is redundant" msg)
|
|
||||||
(when haskell-process-suggest-remove-import-lines
|
|
||||||
(haskell-process-suggest-remove-import session
|
|
||||||
file
|
|
||||||
(match-string 2 msg)
|
|
||||||
line)))
|
|
||||||
((string-match "Warning: orphan instance: " msg)
|
|
||||||
(when haskell-process-suggest-no-warn-orphans
|
|
||||||
(haskell-process-suggest-pragma session "OPTIONS" "-fno-warn-orphans" file)))
|
|
||||||
((or (string-match "against inferred type [‘`‛]\\[Char\\]['’]" msg)
|
|
||||||
(string-match "with actual type [‘`‛]\\[Char\\]['’]" msg))
|
|
||||||
(when haskell-process-suggest-overloaded-strings
|
|
||||||
(haskell-process-suggest-pragma session "LANGUAGE" "OverloadedStrings" file)))
|
|
||||||
((string-match "^Not in scope: .*[‘`‛]\\(.+\\)['’]$" msg)
|
|
||||||
(let* ((match1 (match-string 1 msg))
|
|
||||||
(ident (if (string-match "^[A-Za-z0-9_'.]+\\.\\(.+\\)$" match1)
|
|
||||||
;; Skip qualification.
|
|
||||||
(match-string 1 match1)
|
|
||||||
match1)))
|
|
||||||
(when haskell-process-suggest-hoogle-imports
|
|
||||||
(let ((modules (haskell-process-hoogle-ident ident)))
|
|
||||||
(haskell-process-suggest-imports session file modules ident)))
|
|
||||||
(when haskell-process-suggest-haskell-docs-imports
|
|
||||||
(let ((modules (haskell-process-haskell-docs-ident ident)))
|
|
||||||
(haskell-process-suggest-imports session file modules ident)))
|
|
||||||
(when haskell-process-suggest-hayoo-imports
|
|
||||||
(let ((modules (haskell-process-hayoo-ident ident)))
|
|
||||||
(haskell-process-suggest-imports session file modules ident)))))
|
|
||||||
((string-match "^[ ]+It is a member of the hidden package [‘`‛]\\(.+\\)['’].$" msg)
|
|
||||||
(when haskell-process-suggest-add-package
|
|
||||||
(haskell-process-suggest-add-package session msg)))))
|
|
||||||
|
|
||||||
(defun haskell-process-do-cabal (command)
|
|
||||||
"Run a Cabal command."
|
|
||||||
(let ((process (haskell-interactive-process)))
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (list (haskell-interactive-session) process command 0)
|
|
||||||
|
|
||||||
:go
|
|
||||||
(lambda (state)
|
|
||||||
(haskell-process-send-string
|
|
||||||
(cadr state)
|
|
||||||
(format haskell-process-do-cabal-format-string
|
|
||||||
(haskell-session-cabal-dir (car state))
|
|
||||||
(format "%s %s"
|
|
||||||
(cl-ecase (haskell-process-type)
|
|
||||||
('ghci haskell-process-path-cabal)
|
|
||||||
('cabal-repl haskell-process-path-cabal)
|
|
||||||
('cabal-ghci haskell-process-path-cabal)
|
|
||||||
('cabal-dev haskell-process-path-cabal-dev))
|
|
||||||
(cl-caddr state)))))
|
|
||||||
|
|
||||||
:live
|
|
||||||
(lambda (state buffer)
|
|
||||||
(let ((cmd (replace-regexp-in-string "^\\([a-z]+\\).*"
|
|
||||||
"\\1"
|
|
||||||
(cl-caddr state))))
|
|
||||||
(cond ((or (string= cmd "build")
|
|
||||||
(string= cmd "install"))
|
|
||||||
(haskell-process-live-build (cadr state) buffer t))
|
|
||||||
(t
|
|
||||||
(haskell-process-cabal-live state buffer)))))
|
|
||||||
|
|
||||||
:complete
|
|
||||||
(lambda (state response)
|
|
||||||
(let* ((process (cadr state))
|
|
||||||
(session (haskell-process-session process))
|
|
||||||
(message-count 0)
|
|
||||||
(cursor (haskell-process-response-cursor process)))
|
|
||||||
(haskell-process-set-response-cursor process 0)
|
|
||||||
(while (haskell-process-errors-warnings session process response)
|
|
||||||
(setq message-count (1+ message-count)))
|
|
||||||
(haskell-process-set-response-cursor process cursor)
|
|
||||||
(let ((msg (format "Complete: cabal %s (%s compiler messages)"
|
|
||||||
(cl-caddr state)
|
|
||||||
message-count)))
|
|
||||||
(haskell-interactive-mode-echo session msg)
|
|
||||||
(when (= message-count 0)
|
|
||||||
(haskell-interactive-mode-echo
|
|
||||||
session
|
|
||||||
"No compiler messages, dumping complete output:")
|
|
||||||
(haskell-interactive-mode-echo session response))
|
|
||||||
(haskell-mode-message-line msg)
|
|
||||||
(when (and haskell-notify-p
|
|
||||||
(fboundp 'notifications-notify))
|
|
||||||
(notifications-notify
|
|
||||||
:title (format "*%s*" (haskell-session-name (car state)))
|
|
||||||
:body msg
|
|
||||||
:app-name (cl-ecase (haskell-process-type)
|
|
||||||
('ghci haskell-process-path-cabal)
|
|
||||||
('cabal-repl haskell-process-path-cabal)
|
|
||||||
('cabal-ghci haskell-process-path-cabal)
|
|
||||||
('cabal-dev haskell-process-path-cabal-dev))
|
|
||||||
:app-icon haskell-process-logo)))))))))
|
|
||||||
|
|
||||||
(defun haskell-process-echo-load-message (process buffer echo-in-repl th)
|
|
||||||
"Echo a load message."
|
|
||||||
(let ((session (haskell-process-session process))
|
|
||||||
(module-name (match-string 3 buffer))
|
|
||||||
(file-name (match-string 4 buffer)))
|
|
||||||
(haskell-interactive-show-load-message
|
|
||||||
session
|
|
||||||
'compiling
|
|
||||||
module-name
|
|
||||||
(haskell-session-strip-dir session file-name)
|
|
||||||
echo-in-repl
|
|
||||||
th)))
|
|
||||||
|
|
||||||
(defun haskell-process-extract-modules (buffer)
|
|
||||||
"Extract the modules from the process buffer."
|
|
||||||
(let* ((modules-string (match-string 1 buffer))
|
|
||||||
(modules (split-string modules-string ", ")))
|
|
||||||
(cons modules modules-string)))
|
|
||||||
|
|
||||||
(defun haskell-process-errors-warnings (session process buffer &optional return-only)
|
|
||||||
"Trigger handling type errors or warnings. Either prints the
|
|
||||||
messages in the interactive buffer or if CONT is specified,
|
|
||||||
passes the error onto that."
|
|
||||||
(cond
|
|
||||||
((haskell-process-consume
|
|
||||||
process
|
|
||||||
"\\(Module imports form a cycle:[ \n]+module [^ ]+ ([^)]+)[[:unibyte:][:nonascii:]]+?\\)\nFailed")
|
|
||||||
(let ((err (match-string 1 buffer)))
|
|
||||||
(if (string-match "module [`'‘‛]\\([^ ]+\\)['’`] (\\([^)]+\\))" err)
|
|
||||||
(let* ((default-directory (haskell-session-current-dir session))
|
|
||||||
(module (match-string 1 err))
|
|
||||||
(file (match-string 2 err))
|
|
||||||
(relative-file-name (file-relative-name file)))
|
|
||||||
(unless return-only
|
|
||||||
(haskell-interactive-show-load-message
|
|
||||||
session
|
|
||||||
'import-cycle
|
|
||||||
module
|
|
||||||
relative-file-name
|
|
||||||
nil
|
|
||||||
nil)
|
|
||||||
(haskell-interactive-mode-compile-error
|
|
||||||
session
|
|
||||||
(format "%s:1:0: %s"
|
|
||||||
relative-file-name
|
|
||||||
err)))
|
|
||||||
(list :file file :line 1 :col 0 :msg err :type 'error))
|
|
||||||
t)))
|
|
||||||
((haskell-process-consume
|
|
||||||
process
|
|
||||||
(concat "[\r\n]\\([A-Z]?:?[^ \r\n:][^:\n\r]+\\):\\([0-9()-:]+\\):"
|
|
||||||
"[ \n\r]+\\([[:unibyte:][:nonascii:]]+?\\)\n[^ ]"))
|
|
||||||
(haskell-process-set-response-cursor process
|
|
||||||
(- (haskell-process-response-cursor process) 1))
|
|
||||||
(let* ((buffer (haskell-process-response process))
|
|
||||||
(file (match-string 1 buffer))
|
|
||||||
(location (match-string 2 buffer))
|
|
||||||
(error-msg (match-string 3 buffer))
|
|
||||||
(warning (string-match "^Warning:" error-msg))
|
|
||||||
(splice (string-match "^Splicing " error-msg))
|
|
||||||
(final-msg (format "%s:%s: %s"
|
|
||||||
(haskell-session-strip-dir session file)
|
|
||||||
location
|
|
||||||
error-msg)))
|
|
||||||
(if return-only
|
|
||||||
(let* ((location (haskell-process-parse-error (concat file ":" location ": x")))
|
|
||||||
(file (plist-get location :file))
|
|
||||||
(line (plist-get location :line))
|
|
||||||
(col1 (plist-get location :col)))
|
|
||||||
(list :file file :line line :col col1 :msg error-msg :type (if warning 'warning 'error)))
|
|
||||||
(progn (funcall (cond (warning
|
|
||||||
'haskell-interactive-mode-compile-warning)
|
|
||||||
(splice
|
|
||||||
'haskell-interactive-mode-compile-splice)
|
|
||||||
(t 'haskell-interactive-mode-compile-error))
|
|
||||||
session final-msg)
|
|
||||||
(unless warning
|
|
||||||
(haskell-mode-message-line final-msg))
|
|
||||||
(haskell-process-trigger-suggestions
|
|
||||||
session
|
|
||||||
error-msg
|
|
||||||
file
|
|
||||||
(plist-get (haskell-process-parse-error final-msg) :line))
|
|
||||||
t))))))
|
|
||||||
|
|
||||||
(defun haskell-interactive-show-load-message (session type module-name file-name echo th)
|
|
||||||
"Show the '(Compiling|Loading) X' message."
|
|
||||||
(let ((msg (concat
|
|
||||||
(cl-ecase type
|
|
||||||
('compiling
|
|
||||||
(if haskell-interactive-mode-include-file-name
|
|
||||||
(format "Compiling: %s (%s)" module-name file-name)
|
|
||||||
(format "Compiling: %s" module-name)))
|
|
||||||
('loading (format "Loading: %s" module-name))
|
|
||||||
('import-cycle (format "Module has an import cycle: %s" module-name)))
|
|
||||||
(if th " [TH]" ""))))
|
|
||||||
(haskell-mode-message-line msg)
|
|
||||||
(when haskell-interactive-mode-delete-superseded-errors
|
|
||||||
(haskell-interactive-mode-delete-compile-messages session file-name))
|
|
||||||
(when echo
|
|
||||||
(haskell-interactive-mode-echo session msg))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-process-reload-devel-main ()
|
|
||||||
"Reload the module `DevelMain' and then run
|
|
||||||
`DevelMain.update'. This is for doing live update of the code of
|
|
||||||
servers or GUI applications. Put your development version of the
|
|
||||||
program in `DevelMain', and define `update' to auto-start the
|
|
||||||
program on a new thread, and use the `foreign-store' package to
|
|
||||||
access the running context across :load/:reloads in GHCi."
|
|
||||||
(interactive)
|
|
||||||
(with-current-buffer (or (get-buffer "DevelMain.hs")
|
|
||||||
(if (y-or-n-p "You need to open a buffer named DevelMain.hs. Find now?")
|
|
||||||
(ido-find-file)
|
|
||||||
(error "No DevelMain.hs buffer.")))
|
|
||||||
(let ((session (haskell-interactive-session)))
|
|
||||||
(let ((process (haskell-interactive-process)))
|
|
||||||
(haskell-process-queue-command
|
|
||||||
process
|
|
||||||
(make-haskell-command
|
|
||||||
:state (list :session session
|
|
||||||
:process process
|
|
||||||
:buffer (current-buffer))
|
|
||||||
:go (lambda (state)
|
|
||||||
(haskell-process-send-string (plist-get state ':process)
|
|
||||||
":l DevelMain"))
|
|
||||||
:live (lambda (state buffer)
|
|
||||||
(haskell-process-live-build (plist-get state ':process)
|
|
||||||
buffer
|
|
||||||
nil))
|
|
||||||
:complete (lambda (state response)
|
|
||||||
(haskell-process-load-complete
|
|
||||||
(plist-get state ':session)
|
|
||||||
(plist-get state ':process)
|
|
||||||
response
|
|
||||||
nil
|
|
||||||
(plist-get state ':buffer)
|
|
||||||
(lambda (ok)
|
|
||||||
(when ok
|
|
||||||
(haskell-process-queue-without-filters
|
|
||||||
(haskell-interactive-process)
|
|
||||||
"DevelMain.update")
|
|
||||||
(message "DevelMain updated.")))))))))))
|
|
||||||
|
|
||||||
(provide 'haskell-load)
|
|
Binary file not shown.
@@ -1,158 +0,0 @@
|
|||||||
;;; haskell-menu.el --- A Haskell sessions menu
|
|
||||||
|
|
||||||
;; Copyright (C) 2013 Chris Done
|
|
||||||
|
|
||||||
;; Author: Chris Done <chrisdone@gmail.com>
|
|
||||||
|
|
||||||
;; This file is not part of GNU Emacs.
|
|
||||||
|
|
||||||
;; This file 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, or (at your option)
|
|
||||||
;; any later version.
|
|
||||||
|
|
||||||
;; This file 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 GNU Emacs; see the file COPYING. If not, write to
|
|
||||||
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
||||||
;; Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;;; Todo:
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'cl-lib)
|
|
||||||
(require 'haskell-compat)
|
|
||||||
(require 'haskell-session)
|
|
||||||
(require 'haskell-process)
|
|
||||||
(require 'haskell-interactive-mode)
|
|
||||||
|
|
||||||
(defcustom haskell-menu-buffer-name "*haskell-menu*"
|
|
||||||
"The name of the Haskell session menu buffer"
|
|
||||||
:group 'haskell-interactive
|
|
||||||
:type 'string)
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun haskell-menu ()
|
|
||||||
"Launch the Haskell sessions menu."
|
|
||||||
(interactive)
|
|
||||||
(or (get-buffer haskell-menu-buffer-name)
|
|
||||||
(with-current-buffer (get-buffer-create haskell-menu-buffer-name)
|
|
||||||
(haskell-menu-mode)))
|
|
||||||
(switch-to-buffer-other-window (get-buffer haskell-menu-buffer-name))
|
|
||||||
(haskell-menu-revert-function nil nil))
|
|
||||||
|
|
||||||
(define-derived-mode haskell-menu-mode special-mode "Haskell Session Menu"
|
|
||||||
"Major mode for managing Haskell sessions.
|
|
||||||
Each line describes one session.
|
|
||||||
Letters do not insert themselves; instead, they are commands."
|
|
||||||
(setq buffer-read-only t)
|
|
||||||
(set (make-local-variable 'revert-buffer-function)
|
|
||||||
'haskell-menu-revert-function)
|
|
||||||
(setq truncate-lines t)
|
|
||||||
(haskell-menu-revert-function nil t))
|
|
||||||
|
|
||||||
(suppress-keymap haskell-menu-mode-map t)
|
|
||||||
(define-key haskell-menu-mode-map (kbd "n") 'next-line)
|
|
||||||
(define-key haskell-menu-mode-map (kbd "p") 'previous-line)
|
|
||||||
(define-key haskell-menu-mode-map (kbd "RET") 'haskell-menu-mode-ret)
|
|
||||||
|
|
||||||
(defun haskell-menu-revert-function (arg1 arg2)
|
|
||||||
"Function to refresh the display."
|
|
||||||
(let ((buffer-read-only nil)
|
|
||||||
(orig-line (line-number-at-pos))
|
|
||||||
(orig-col (current-column)))
|
|
||||||
(or (eq buffer-undo-list t)
|
|
||||||
(setq buffer-undo-list nil))
|
|
||||||
(erase-buffer)
|
|
||||||
(haskell-menu-insert-menu)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(forward-line (1- orig-line))
|
|
||||||
(forward-char orig-col)))
|
|
||||||
|
|
||||||
(defun haskell-menu-insert-menu ()
|
|
||||||
"Insert the Haskell sessions menu to the current buffer."
|
|
||||||
(if (null haskell-sessions)
|
|
||||||
(insert "No Haskell sessions.")
|
|
||||||
(haskell-menu-tabulate
|
|
||||||
(list "Name" "PID" "Time" "RSS" "Cabal directory" "Working directory" "Command")
|
|
||||||
(mapcar (lambda (session)
|
|
||||||
(let ((process (haskell-process-process (haskell-session-process session))))
|
|
||||||
(cond
|
|
||||||
(process
|
|
||||||
(let ((id (process-id process)))
|
|
||||||
(list (propertize (haskell-session-name session) 'face 'buffer-menu-buffer)
|
|
||||||
(if (process-live-p process) (number-to-string id) "-")
|
|
||||||
(if (process-live-p process)
|
|
||||||
(format-time-string "%H:%M:%S"
|
|
||||||
(encode-time (cl-caddr (assoc 'etime (process-attributes id)))
|
|
||||||
0 0 0 0 0))
|
|
||||||
"-")
|
|
||||||
(if (process-live-p process)
|
|
||||||
(concat (number-to-string (/ (cdr (assoc 'rss (process-attributes id)))
|
|
||||||
1024))
|
|
||||||
"MB")
|
|
||||||
"-")
|
|
||||||
(haskell-session-cabal-dir session)
|
|
||||||
(haskell-session-current-dir session)
|
|
||||||
(mapconcat 'identity (process-command process) " "))))
|
|
||||||
(t (list (propertize (haskell-session-name session) 'face 'buffer-menu-buffer)
|
|
||||||
"—"
|
|
||||||
"—"
|
|
||||||
"—"
|
|
||||||
(haskell-session-cabal-dir session)
|
|
||||||
(haskell-session-current-dir session))))))
|
|
||||||
haskell-sessions))))
|
|
||||||
|
|
||||||
(defun haskell-menu-tabulate (headings rows)
|
|
||||||
"Prints a list of lists as a formatted table to the current buffer."
|
|
||||||
(let* ((columns (length headings))
|
|
||||||
(widths (make-list columns 0)))
|
|
||||||
;; Calculate column widths. This is kind of hideous.
|
|
||||||
(dolist (row rows)
|
|
||||||
(setq widths
|
|
||||||
(let ((list (list)))
|
|
||||||
(dotimes (i columns)
|
|
||||||
(setq list (cons (max (nth i widths)
|
|
||||||
(1+ (length (nth i row)))
|
|
||||||
(1+ (length (nth i headings))))
|
|
||||||
list)))
|
|
||||||
(reverse list))))
|
|
||||||
;; Print headings.
|
|
||||||
(let ((heading (propertize " " 'display '(space :align-to 0))))
|
|
||||||
(dotimes (i columns)
|
|
||||||
(setq heading (concat heading
|
|
||||||
(format (concat "%-" (number-to-string (nth i widths)) "s")
|
|
||||||
(nth i headings)))))
|
|
||||||
(setq header-line-format heading))
|
|
||||||
;; Print tabulated rows.
|
|
||||||
(dolist (row rows)
|
|
||||||
(dotimes (i columns)
|
|
||||||
(insert (format (concat "%-" (number-to-string (nth i widths)) "s")
|
|
||||||
(nth i row))))
|
|
||||||
(insert "\n"))))
|
|
||||||
|
|
||||||
(defun haskell-menu-mode-ret ()
|
|
||||||
"Handle RET key."
|
|
||||||
(interactive)
|
|
||||||
(let* ((name (save-excursion
|
|
||||||
(goto-char (line-beginning-position))
|
|
||||||
(buffer-substring-no-properties (point)
|
|
||||||
(progn (search-forward " ")
|
|
||||||
(forward-char -1)
|
|
||||||
(point)))))
|
|
||||||
(session (car (cl-remove-if-not (lambda (session)
|
|
||||||
(string= (haskell-session-name session)
|
|
||||||
name))
|
|
||||||
haskell-sessions))))
|
|
||||||
(switch-to-buffer (haskell-session-interactive-buffer session))))
|
|
||||||
|
|
||||||
(provide 'haskell-menu)
|
|
||||||
|
|
||||||
;;; haskell-menu.el ends here
|
|
Binary file not shown.
@@ -1,953 +0,0 @@
|
|||||||
;;; haskell-mode-autoloads.el --- automatically extracted autoloads
|
|
||||||
;;
|
|
||||||
;;; Code:
|
|
||||||
(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
|
|
||||||
|
|
||||||
;;;### (autoloads nil "ghc-core" "ghc-core.el" (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from ghc-core.el
|
|
||||||
|
|
||||||
(autoload 'ghc-core-create-core "ghc-core" "\
|
|
||||||
Compile and load the current buffer as tidy core.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.hcr\\'" . ghc-core-mode))
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.dump-simpl\\'" . ghc-core-mode))
|
|
||||||
|
|
||||||
(autoload 'ghc-core-mode "ghc-core" "\
|
|
||||||
Major mode for GHC Core files.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "ghci-script-mode" "ghci-script-mode.el" (21860
|
|
||||||
;;;;;; 25846 0 0))
|
|
||||||
;;; Generated autoloads from ghci-script-mode.el
|
|
||||||
|
|
||||||
(autoload 'ghci-script-mode "ghci-script-mode" "\
|
|
||||||
Major mode for working with .ghci files.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.ghci\\'" . ghci-script-mode))
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell" "haskell.el" (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell.el
|
|
||||||
|
|
||||||
(autoload 'interactive-haskell-mode "haskell" "\
|
|
||||||
Minor mode for enabling haskell-process interaction.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-interactive-mode-return "haskell" "\
|
|
||||||
Handle the return key.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-session-kill "haskell" "\
|
|
||||||
Kill the session process and buffer, delete the session.
|
|
||||||
0. Prompt to kill all associated buffers.
|
|
||||||
1. Kill the process.
|
|
||||||
2. Kill the interactive buffer.
|
|
||||||
3. Walk through all the related buffers and set their haskell-session to nil.
|
|
||||||
4. Remove the session from the sessions list.
|
|
||||||
|
|
||||||
\(fn &optional LEAVE-INTERACTIVE-BUFFER)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-interactive-kill "haskell" "\
|
|
||||||
Kill the buffer and (maybe) the session.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-session "haskell" "\
|
|
||||||
Get the Haskell session, prompt if there isn't one or fail.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-interactive-switch "haskell" "\
|
|
||||||
Switch to the interactive mode for this session.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-session-change "haskell" "\
|
|
||||||
Change the session for the current buffer.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-kill-session-process "haskell" "\
|
|
||||||
Kill the process.
|
|
||||||
|
|
||||||
\(fn &optional SESSION)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-interactive-mode-visit-error "haskell" "\
|
|
||||||
Visit the buffer of the current (or last) error message.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-contextual-space "haskell" "\
|
|
||||||
Contextually do clever stuff when hitting space.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-jump-to-tag "haskell" "\
|
|
||||||
Jump to the tag of the given identifier.
|
|
||||||
|
|
||||||
\(fn &optional NEXT-P)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-after-save-handler "haskell" "\
|
|
||||||
Function that will be called after buffer's saving.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-tag-find "haskell" "\
|
|
||||||
The tag find function, specific for the particular session.
|
|
||||||
|
|
||||||
\(fn &optional NEXT-P)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-interactive-bring "haskell" "\
|
|
||||||
Bring up the interactive mode for this session.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-load-file "haskell" "\
|
|
||||||
Load the current buffer file.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-reload-file "haskell" "\
|
|
||||||
Re-load the current buffer file.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-load-or-reload "haskell" "\
|
|
||||||
Load or reload. Universal argument toggles which.
|
|
||||||
|
|
||||||
\(fn &optional TOGGLE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-cabal-build "haskell" "\
|
|
||||||
Build the Cabal project.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-cabal "haskell" "\
|
|
||||||
Prompts for a Cabal command to run.
|
|
||||||
|
|
||||||
\(fn P)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-minimal-imports "haskell" "\
|
|
||||||
Dump minimal imports.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-align-imports" "haskell-align-imports.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-align-imports.el
|
|
||||||
|
|
||||||
(autoload 'haskell-align-imports "haskell-align-imports" "\
|
|
||||||
Align all the imports in the buffer.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-c" "haskell-c.el" (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-c.el
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.hsc\\'" . haskell-c-mode))
|
|
||||||
|
|
||||||
(autoload 'haskell-c-mode "haskell-c" "\
|
|
||||||
Major mode for Haskell FFI files.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-cabal" "haskell-cabal.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from haskell-cabal.el
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode))
|
|
||||||
|
|
||||||
(autoload 'haskell-cabal-mode "haskell-cabal" "\
|
|
||||||
Major mode for Cabal package description files.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-guess-setting "haskell-cabal" "\
|
|
||||||
Guess the specified setting of this project.
|
|
||||||
If there is no valid .cabal file to get the setting from (or
|
|
||||||
there is no corresponding setting with that name in the .cabal
|
|
||||||
file), then this function returns nil.
|
|
||||||
|
|
||||||
\(fn NAME)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-cabal-get-dir "haskell-cabal" "\
|
|
||||||
Get the Cabal dir for a new project. Various ways of figuring this out,
|
|
||||||
and indeed just prompting the user. Do them all.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-cabal-visit-file "haskell-cabal" "\
|
|
||||||
Locate and visit package description file for file visited by current buffer.
|
|
||||||
This uses `haskell-cabal-find-file' to locate the closest
|
|
||||||
\".cabal\" file and open it. This command assumes a common Cabal
|
|
||||||
project structure where the \".cabal\" file is in the top-folder
|
|
||||||
of the project, and all files related to the project are in or
|
|
||||||
below the top-folder. If called with non-nil prefix argument
|
|
||||||
OTHER-WINDOW use `find-file-other-window'.
|
|
||||||
|
|
||||||
\(fn OTHER-WINDOW)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-commands" "haskell-commands.el" (21860
|
|
||||||
;;;;;; 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-commands.el
|
|
||||||
|
|
||||||
(autoload 'haskell-process-restart "haskell-commands" "\
|
|
||||||
Restart the inferior Haskell process.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-clear "haskell-commands" "\
|
|
||||||
Clear the current process.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-interrupt "haskell-commands" "\
|
|
||||||
Interrupt the process (SIGINT).
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-touch-buffer "haskell-commands" "\
|
|
||||||
Updates mtime on the file for BUFFER by queing a touch on
|
|
||||||
PROCESS.
|
|
||||||
|
|
||||||
\(fn PROCESS BUFFER)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-describe "haskell-commands" "\
|
|
||||||
Describe the given identifier.
|
|
||||||
|
|
||||||
\(fn IDENT)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-rgrep "haskell-commands" "\
|
|
||||||
Grep the effective project for the symbol at point. Very
|
|
||||||
useful for codebase navigation. Prompts for an arbitrary regexp
|
|
||||||
given a prefix arg.
|
|
||||||
|
|
||||||
\(fn &optional PROMPT)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-do-info "haskell-commands" "\
|
|
||||||
Print info on the identifier at point.
|
|
||||||
If PROMPT-VALUE is non-nil, request identifier via mini-buffer.
|
|
||||||
|
|
||||||
\(fn &optional PROMPT-VALUE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-do-type "haskell-commands" "\
|
|
||||||
Print the type of the given expression.
|
|
||||||
|
|
||||||
\(fn &optional INSERT-VALUE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-jump-to-def-or-tag "haskell-commands" "\
|
|
||||||
Jump to the definition (by consulting GHCi), or (fallback)
|
|
||||||
jump to the tag.
|
|
||||||
|
|
||||||
Remember: If GHCi is busy doing something, this will delay, but
|
|
||||||
it will always be accurate, in contrast to tags, which always
|
|
||||||
work but are not always accurate.
|
|
||||||
If the definition or tag is found, the location from which you jumped
|
|
||||||
will be pushed onto `xref--marker-ring', so you can return to that
|
|
||||||
position with `xref-pop-marker-stack'.
|
|
||||||
|
|
||||||
\(fn &optional NEXT-P)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-goto-loc "haskell-commands" "\
|
|
||||||
Go to the location of the thing at point. Requires the :loc-at
|
|
||||||
command from GHCi.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-jump-to-def "haskell-commands" "\
|
|
||||||
Jump to definition of identifier at point.
|
|
||||||
|
|
||||||
\(fn IDENT)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-cd "haskell-commands" "\
|
|
||||||
Change directory.
|
|
||||||
|
|
||||||
\(fn &optional NOT-INTERACTIVE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-cabal-macros "haskell-commands" "\
|
|
||||||
Send the cabal macros string.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-show-type-at "haskell-commands" "\
|
|
||||||
Show the type of the thing at point.
|
|
||||||
|
|
||||||
\(fn &optional INSERT-VALUE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-generate-tags "haskell-commands" "\
|
|
||||||
Regenerate the TAGS table.
|
|
||||||
|
|
||||||
\(fn &optional AND-THEN-FIND-THIS-TAG)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-unignore "haskell-commands" "\
|
|
||||||
Unignore any files that were specified as being ignored by the
|
|
||||||
inferior GHCi process.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-session-change-target "haskell-commands" "\
|
|
||||||
Set the build target for cabal repl
|
|
||||||
|
|
||||||
\(fn TARGET)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-stylish-buffer "haskell-commands" "\
|
|
||||||
Apply stylish-haskell to the current buffer.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-find-uses "haskell-commands" "\
|
|
||||||
Find uses of the identifier at point, highlight them all.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-compile" "haskell-compile.el" (21860
|
|
||||||
;;;;;; 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-compile.el
|
|
||||||
|
|
||||||
(autoload 'haskell-compile "haskell-compile" "\
|
|
||||||
Compile the Haskell program including the current buffer.
|
|
||||||
Tries to locate the next cabal description in current or parent
|
|
||||||
folders via `haskell-cabal-find-dir' and if found, invoke
|
|
||||||
`haskell-compile-cabal-build-command' from the cabal package root
|
|
||||||
folder. If no cabal package could be detected,
|
|
||||||
`haskell-compile-command' is used instead.
|
|
||||||
|
|
||||||
If prefix argument EDIT-COMMAND is non-nil (and not a negative
|
|
||||||
prefix `-'), `haskell-compile' prompts for custom compile
|
|
||||||
command.
|
|
||||||
|
|
||||||
If EDIT-COMMAND contains the negative prefix argument `-',
|
|
||||||
`haskell-compile' calls the alternative command defined in
|
|
||||||
`haskell-compile-cabal-build-alt-command' if a cabal package was
|
|
||||||
detected.
|
|
||||||
|
|
||||||
`haskell-compile' uses `haskell-compilation-mode' which is
|
|
||||||
derived from `compilation-mode'. See Info
|
|
||||||
node `(haskell-mode)compilation' for more details.
|
|
||||||
|
|
||||||
\(fn &optional EDIT-COMMAND)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-customize" "haskell-customize.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-customize.el
|
|
||||||
|
|
||||||
(autoload 'haskell-customize "haskell-customize" "\
|
|
||||||
Browse the haskell customize sub-tree.
|
|
||||||
This calls 'customize-browse' with haskell as argument and makes
|
|
||||||
sure all haskell customize definitions have been loaded.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-decl-scan" "haskell-decl-scan.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-decl-scan.el
|
|
||||||
|
|
||||||
(autoload 'haskell-ds-create-imenu-index "haskell-decl-scan" "\
|
|
||||||
Function for finding `imenu' declarations in Haskell mode.
|
|
||||||
Finds all declarations (classes, variables, imports, instances and
|
|
||||||
datatypes) in a Haskell file for the `imenu' package.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'turn-on-haskell-decl-scan "haskell-decl-scan" "\
|
|
||||||
Unconditionally activate `haskell-decl-scan-mode'.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-decl-scan-mode "haskell-decl-scan" "\
|
|
||||||
Toggle Haskell declaration scanning minor mode on or off.
|
|
||||||
With a prefix argument ARG, enable minor mode if ARG is
|
|
||||||
positive, and disable it otherwise. If called from Lisp, enable
|
|
||||||
the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'.
|
|
||||||
|
|
||||||
See also info node `(haskell-mode)haskell-decl-scan-mode' for
|
|
||||||
more details about this minor mode.
|
|
||||||
|
|
||||||
Top-level declarations are scanned and listed in the menu item
|
|
||||||
\"Declarations\" (if enabled via option
|
|
||||||
`haskell-decl-scan-add-to-menubar'). Selecting an item from this
|
|
||||||
menu will take point to the start of the declaration.
|
|
||||||
|
|
||||||
\\[beginning-of-defun] and \\[end-of-defun] move forward and backward to the start of a declaration.
|
|
||||||
|
|
||||||
This may link with `haskell-doc-mode'.
|
|
||||||
|
|
||||||
For non-literate and LaTeX-style literate scripts, we assume the
|
|
||||||
common convention that top-level declarations start at the first
|
|
||||||
column. For Bird-style literate scripts, we assume the common
|
|
||||||
convention that top-level declarations start at the third column,
|
|
||||||
ie. after \"> \".
|
|
||||||
|
|
||||||
Anything in `font-lock-comment-face' is not considered for a
|
|
||||||
declaration. Therefore, using Haskell font locking with comments
|
|
||||||
coloured in `font-lock-comment-face' improves declaration scanning.
|
|
||||||
|
|
||||||
Literate Haskell scripts are supported: If the value of
|
|
||||||
`haskell-literate' (set automatically by `literate-haskell-mode')
|
|
||||||
is `bird', a Bird-style literate script is assumed. If it is nil
|
|
||||||
or `tex', a non-literate or LaTeX-style literate script is
|
|
||||||
assumed, respectively.
|
|
||||||
|
|
||||||
Invokes `haskell-decl-scan-mode-hook' on activation.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-doc" "haskell-doc.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from haskell-doc.el
|
|
||||||
|
|
||||||
(autoload 'haskell-doc-mode "haskell-doc" "\
|
|
||||||
Enter `haskell-doc-mode' for showing fct types in the echo area.
|
|
||||||
See variable docstring.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
(defalias 'turn-on-haskell-doc-mode 'haskell-doc-mode)
|
|
||||||
|
|
||||||
(defalias 'turn-on-haskell-doc 'haskell-doc-mode)
|
|
||||||
|
|
||||||
(autoload 'haskell-doc-current-info "haskell-doc" "\
|
|
||||||
Return the info about symbol at point.
|
|
||||||
Meant for `eldoc-documentation-function'.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-doc-show-type "haskell-doc" "\
|
|
||||||
Show the type of the function near point.
|
|
||||||
For the function under point, show the type in the echo area.
|
|
||||||
This information is extracted from the `haskell-doc-prelude-types' alist
|
|
||||||
of prelude functions and their types, or from the local functions in the
|
|
||||||
current buffer.
|
|
||||||
|
|
||||||
\(fn &optional SYM)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-font-lock" "haskell-font-lock.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-font-lock.el
|
|
||||||
|
|
||||||
(autoload 'haskell-font-lock-choose-keywords "haskell-font-lock" "\
|
|
||||||
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-indent" "haskell-indent.el" (21860
|
|
||||||
;;;;;; 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-indent.el
|
|
||||||
|
|
||||||
(autoload 'turn-on-haskell-indent "haskell-indent" "\
|
|
||||||
Turn on ``intelligent'' Haskell indentation mode.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-indent-mode "haskell-indent" "\
|
|
||||||
``Intelligent'' Haskell indentation mode.
|
|
||||||
This deals with the layout rule of Haskell.
|
|
||||||
\\[haskell-indent-cycle] starts the cycle which proposes new
|
|
||||||
possibilities as long as the TAB key is pressed. Any other key
|
|
||||||
or mouse click terminates the cycle and is interpreted except for
|
|
||||||
RET which merely exits the cycle.
|
|
||||||
Other special keys are:
|
|
||||||
\\[haskell-indent-insert-equal]
|
|
||||||
inserts an =
|
|
||||||
\\[haskell-indent-insert-guard]
|
|
||||||
inserts an |
|
|
||||||
\\[haskell-indent-insert-otherwise]
|
|
||||||
inserts an | otherwise =
|
|
||||||
these functions also align the guards and rhs of the current definition
|
|
||||||
\\[haskell-indent-insert-where]
|
|
||||||
inserts a where keyword
|
|
||||||
\\[haskell-indent-align-guards-and-rhs]
|
|
||||||
aligns the guards and rhs of the region
|
|
||||||
\\[haskell-indent-put-region-in-literate]
|
|
||||||
makes the region a piece of literate code in a literate script
|
|
||||||
|
|
||||||
Invokes `haskell-indent-hook' if not nil.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-indentation" "haskell-indentation.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-indentation.el
|
|
||||||
|
|
||||||
(autoload 'haskell-indentation-mode "haskell-indentation" "\
|
|
||||||
Haskell indentation mode that deals with the layout rule.
|
|
||||||
It rebinds RET, DEL and BACKSPACE, so that indentations can be
|
|
||||||
set and deleted as if they were real tabs. It supports
|
|
||||||
autofill-mode.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
(autoload 'turn-on-haskell-indentation "haskell-indentation" "\
|
|
||||||
Turn on the haskell-indentation minor mode.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-interactive-mode" "haskell-interactive-mode.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-interactive-mode.el
|
|
||||||
|
|
||||||
(autoload 'haskell-interactive-mode-reset-error "haskell-interactive-mode" "\
|
|
||||||
Reset the error cursor position.
|
|
||||||
|
|
||||||
\(fn SESSION)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-interactive-mode-echo "haskell-interactive-mode" "\
|
|
||||||
Echo a read only piece of text before the prompt.
|
|
||||||
|
|
||||||
\(fn SESSION MESSAGE &optional MODE)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-process-do-simple-echo "haskell-interactive-mode" "\
|
|
||||||
Send LINE to the GHCi process and echo the result in some
|
|
||||||
fashion, such as printing in the minibuffer, or using
|
|
||||||
haskell-present, depending on configuration.
|
|
||||||
|
|
||||||
\(fn LINE &optional MODE)" nil nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-load" "haskell-load.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from haskell-load.el
|
|
||||||
|
|
||||||
(autoload 'haskell-process-reload-devel-main "haskell-load" "\
|
|
||||||
Reload the module `DevelMain' and then run
|
|
||||||
`DevelMain.update'. This is for doing live update of the code of
|
|
||||||
servers or GUI applications. Put your development version of the
|
|
||||||
program in `DevelMain', and define `update' to auto-start the
|
|
||||||
program on a new thread, and use the `foreign-store' package to
|
|
||||||
access the running context across :load/:reloads in GHCi.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-menu" "haskell-menu.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from haskell-menu.el
|
|
||||||
|
|
||||||
(autoload 'haskell-menu "haskell-menu" "\
|
|
||||||
Launch the Haskell sessions menu.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-mode" "haskell-mode.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from haskell-mode.el
|
|
||||||
|
|
||||||
(autoload 'haskell-version "haskell-mode" "\
|
|
||||||
Show the `haskell-mode` version in the echo area.
|
|
||||||
With prefix argument HERE, insert it at point.
|
|
||||||
When FULL is non-nil, use a verbose version string.
|
|
||||||
When MESSAGE is non-nil, display a message with the version.
|
|
||||||
|
|
||||||
\(fn &optional HERE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-mode-view-news "haskell-mode" "\
|
|
||||||
Display information on recent changes to haskell-mode.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(defvar haskell-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-.") 'haskell-mode-format-imports) (define-key map [remap delete-indentation] 'haskell-delete-indentation) (define-key map (kbd "C-c C-l") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-b") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-v") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-t") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-i") 'haskell-mode-enable-process-minor-mode) map) "\
|
|
||||||
Keymap used in Haskell mode.")
|
|
||||||
|
|
||||||
(autoload 'haskell-mode "haskell-mode" "\
|
|
||||||
Major mode for editing Haskell programs.
|
|
||||||
|
|
||||||
See also Info node `(haskell-mode)Getting Started' for more
|
|
||||||
information about this mode.
|
|
||||||
|
|
||||||
\\<haskell-mode-map>
|
|
||||||
Literate scripts are supported via `literate-haskell-mode'.
|
|
||||||
The variable `haskell-literate' indicates the style of the script in the
|
|
||||||
current buffer. See the documentation on this variable for more details.
|
|
||||||
|
|
||||||
Use `haskell-version' to find out what version of Haskell mode you are
|
|
||||||
currently using.
|
|
||||||
|
|
||||||
Additional Haskell mode modules can be hooked in via `haskell-mode-hook';
|
|
||||||
see documentation for that variable for more details.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'literate-haskell-mode "haskell-mode" "\
|
|
||||||
As `haskell-mode' but for literate scripts.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.[gh]s\\'" . haskell-mode))
|
|
||||||
|
|
||||||
(add-to-list 'auto-mode-alist '("\\.l[gh]s\\'" . literate-haskell-mode))
|
|
||||||
|
|
||||||
(add-to-list 'interpreter-mode-alist '("runghc" . haskell-mode))
|
|
||||||
|
|
||||||
(add-to-list 'interpreter-mode-alist '("runhaskell" . haskell-mode))
|
|
||||||
|
|
||||||
(add-to-list 'completion-ignored-extensions ".hi")
|
|
||||||
|
|
||||||
(autoload 'haskell-hoogle "haskell-mode" "\
|
|
||||||
Do a Hoogle search for QUERY.
|
|
||||||
When `haskell-hoogle-command' is non-nil, this command runs
|
|
||||||
that. Otherwise, it opens a hoogle search result in the browser.
|
|
||||||
|
|
||||||
If prefix argument INFO is given, then `haskell-hoogle-command'
|
|
||||||
is asked to show extra info for the items matching QUERY..
|
|
||||||
|
|
||||||
\(fn QUERY &optional INFO)" t nil)
|
|
||||||
|
|
||||||
(defalias 'hoogle 'haskell-hoogle)
|
|
||||||
|
|
||||||
(autoload 'hoogle-lookup-from-local "haskell-mode" "\
|
|
||||||
Lookup by local hoogle.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-hayoo "haskell-mode" "\
|
|
||||||
Do a Hayoo search for QUERY.
|
|
||||||
|
|
||||||
\(fn QUERY)" t nil)
|
|
||||||
|
|
||||||
(defalias 'hayoo 'haskell-hayoo)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-modules" "haskell-modules.el" (21860
|
|
||||||
;;;;;; 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-modules.el
|
|
||||||
|
|
||||||
(autoload 'haskell-session-installed-modules "haskell-modules" "\
|
|
||||||
Get the modules installed in the current package set.
|
|
||||||
If DONTCREATE is non-nil don't create a new session.
|
|
||||||
|
|
||||||
\(fn SESSION &optional DONTCREATE)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-session-all-modules "haskell-modules" "\
|
|
||||||
Get all modules -- installed or in the current project.
|
|
||||||
If DONTCREATE is non-nil don't create a new session.
|
|
||||||
|
|
||||||
\(fn SESSION &optional DONTCREATE)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-session-project-modules "haskell-modules" "\
|
|
||||||
Get the modules of the current project.
|
|
||||||
If DONTCREATE is non-nil don't create a new session.
|
|
||||||
|
|
||||||
\(fn SESSION &optional DONTCREATE)" nil nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-move-nested" "haskell-move-nested.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-move-nested.el
|
|
||||||
|
|
||||||
(autoload 'haskell-move-nested "haskell-move-nested" "\
|
|
||||||
Shift the nested off-side-rule block adjacent to point by COLS columns to the right.
|
|
||||||
|
|
||||||
In Transient Mark mode, if the mark is active, operate on the contents
|
|
||||||
of the region instead.
|
|
||||||
|
|
||||||
\(fn COLS)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-move-nested-right "haskell-move-nested" "\
|
|
||||||
Increase indentation of the following off-side-rule block adjacent to point.
|
|
||||||
|
|
||||||
Use a numeric prefix argument to indicate amount of indentation to apply.
|
|
||||||
|
|
||||||
In Transient Mark mode, if the mark is active, operate on the contents
|
|
||||||
of the region instead.
|
|
||||||
|
|
||||||
\(fn COLS)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-move-nested-left "haskell-move-nested" "\
|
|
||||||
Decrease indentation of the following off-side-rule block adjacent to point.
|
|
||||||
|
|
||||||
Use a numeric prefix argument to indicate amount of indentation to apply.
|
|
||||||
|
|
||||||
In Transient Mark mode, if the mark is active, operate on the contents
|
|
||||||
of the region instead.
|
|
||||||
|
|
||||||
\(fn COLS)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-navigate-imports" "haskell-navigate-imports.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-navigate-imports.el
|
|
||||||
|
|
||||||
(autoload 'haskell-navigate-imports "haskell-navigate-imports" "\
|
|
||||||
Cycle the Haskell import lines or return to point (with prefix arg).
|
|
||||||
|
|
||||||
\(fn &optional RETURN)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-navigate-imports-go "haskell-navigate-imports" "\
|
|
||||||
Go to the first line of a list of consequtive import lines. Cycles.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-navigate-imports-return "haskell-navigate-imports" "\
|
|
||||||
Return to the non-import point we were at before going to the module list.
|
|
||||||
If we were originally at an import list, we can just cycle through easily.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-session" "haskell-session.el" (21860
|
|
||||||
;;;;;; 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-session.el
|
|
||||||
|
|
||||||
(autoload 'haskell-session-maybe "haskell-session" "\
|
|
||||||
Maybe get the Haskell session, return nil if there isn't one.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-session-process "haskell-session" "\
|
|
||||||
Get the session process.
|
|
||||||
|
|
||||||
\(fn S)" nil nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-show" "haskell-show.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from haskell-show.el
|
|
||||||
|
|
||||||
(autoload 'haskell-show-replace "haskell-show" "\
|
|
||||||
Replace the given region containing a Show value with a pretty
|
|
||||||
printed collapsible version.
|
|
||||||
|
|
||||||
\(fn START END)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-show-parse-and-insert "haskell-show" "\
|
|
||||||
Parse a `string' containing a Show instance value and insert
|
|
||||||
it pretty printed into the current buffer.
|
|
||||||
|
|
||||||
\(fn GIVEN)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-show-parse "haskell-show" "\
|
|
||||||
Parse the given input into a tree.
|
|
||||||
|
|
||||||
\(fn GIVEN)" nil nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-simple-indent" "haskell-simple-indent.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-simple-indent.el
|
|
||||||
|
|
||||||
(autoload 'haskell-simple-indent-mode "haskell-simple-indent" "\
|
|
||||||
Simple Haskell indentation mode that uses simple heuristic.
|
|
||||||
In this minor mode, `indent-for-tab-command' (bound to <tab> by
|
|
||||||
default) will move the cursor to the next indent point in the
|
|
||||||
previous nonblank line, whereas `haskell-simple-indent-backtab'
|
|
||||||
\(bound to <backtab> by default) will move the cursor the
|
|
||||||
previous indent point. An indent point is a non-whitespace
|
|
||||||
character following whitespace.
|
|
||||||
|
|
||||||
Runs `haskell-simple-indent-hook' on activation.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
(autoload 'turn-on-haskell-simple-indent "haskell-simple-indent" "\
|
|
||||||
Turn on function `haskell-simple-indent-mode'.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-sort-imports" "haskell-sort-imports.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-sort-imports.el
|
|
||||||
|
|
||||||
(autoload 'haskell-sort-imports "haskell-sort-imports" "\
|
|
||||||
Sort the import list at point. It sorts the current group
|
|
||||||
i.e. an import list separated by blank lines on either side.
|
|
||||||
|
|
||||||
If the region is active, it will restrict the imports to sort
|
|
||||||
within that region.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-string" "haskell-string.el" (21860
|
|
||||||
;;;;;; 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-string.el
|
|
||||||
|
|
||||||
(autoload 'haskell-trim "haskell-string" "\
|
|
||||||
|
|
||||||
|
|
||||||
\(fn STRING)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-string-take "haskell-string" "\
|
|
||||||
Take n chars from string.
|
|
||||||
|
|
||||||
\(fn STRING N)" nil nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-unicode-input-method" "haskell-unicode-input-method.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from haskell-unicode-input-method.el
|
|
||||||
|
|
||||||
(autoload 'turn-on-haskell-unicode-input-method "haskell-unicode-input-method" "\
|
|
||||||
Set input method `haskell-unicode'.
|
|
||||||
See Info node `Unicode(haskell-mode)' for more details.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "haskell-yas" "haskell-yas.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from haskell-yas.el
|
|
||||||
|
|
||||||
(autoload 'haskell-yas-complete "haskell-yas" "\
|
|
||||||
|
|
||||||
|
|
||||||
\(fn &rest ARGS)" nil nil)
|
|
||||||
|
|
||||||
(autoload 'haskell-snippets-initialize "haskell-yas" "\
|
|
||||||
Register haskell snippets with yasnippet.
|
|
||||||
|
|
||||||
\(fn)" nil nil)
|
|
||||||
|
|
||||||
(eval-after-load 'yasnippet '(haskell-snippets-initialize))
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "highlight-uses-mode" "highlight-uses-mode.el"
|
|
||||||
;;;;;; (21860 25846 0 0))
|
|
||||||
;;; Generated autoloads from highlight-uses-mode.el
|
|
||||||
|
|
||||||
(autoload 'highlight-uses-mode "highlight-uses-mode" "\
|
|
||||||
Minor mode for highlighting and jumping between uses.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil "inf-haskell" "inf-haskell.el" (21860 25846
|
|
||||||
;;;;;; 0 0))
|
|
||||||
;;; Generated autoloads from inf-haskell.el
|
|
||||||
|
|
||||||
(defalias 'run-haskell 'switch-to-haskell)
|
|
||||||
|
|
||||||
(autoload 'switch-to-haskell "inf-haskell" "\
|
|
||||||
Show the inferior-haskell buffer. Start the process if needed.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-load-file "inf-haskell" "\
|
|
||||||
Pass the current buffer's file to the inferior haskell process.
|
|
||||||
If prefix arg \\[universal-argument] is given, just reload the previous file.
|
|
||||||
|
|
||||||
\(fn &optional RELOAD)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-load-and-run "inf-haskell" "\
|
|
||||||
Pass the current buffer's file to haskell and then run a COMMAND.
|
|
||||||
|
|
||||||
\(fn COMMAND)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-send-decl "inf-haskell" "\
|
|
||||||
Send current declaration to inferior-haskell process.
|
|
||||||
|
|
||||||
\(fn)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-type "inf-haskell" "\
|
|
||||||
Query the haskell process for the type of the given expression.
|
|
||||||
If optional argument `insert-value' is non-nil, insert the type above point
|
|
||||||
in the buffer. This can be done interactively with the \\[universal-argument] prefix.
|
|
||||||
The returned info is cached for reuse by `haskell-doc-mode'.
|
|
||||||
|
|
||||||
\(fn EXPR &optional INSERT-VALUE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-kind "inf-haskell" "\
|
|
||||||
Query the haskell process for the kind of the given expression.
|
|
||||||
|
|
||||||
\(fn TYPE)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-info "inf-haskell" "\
|
|
||||||
Query the haskell process for the info of the given expression.
|
|
||||||
|
|
||||||
\(fn SYM)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-find-definition "inf-haskell" "\
|
|
||||||
Attempt to locate and jump to the definition of the given expression.
|
|
||||||
|
|
||||||
\(fn SYM)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inferior-haskell-find-haddock "inf-haskell" "\
|
|
||||||
Find and open the Haddock documentation of SYM.
|
|
||||||
Make sure to load the file into GHCi or Hugs first by using C-c C-l.
|
|
||||||
Only works for functions in a package installed with ghc-pkg, or
|
|
||||||
whatever the value of `haskell-package-manager-name' is.
|
|
||||||
|
|
||||||
This function needs to find which package a given module belongs
|
|
||||||
to. In order to do this, it computes a module-to-package lookup
|
|
||||||
alist, which is expensive to compute (it takes upwards of five
|
|
||||||
seconds with more than about thirty installed packages). As a
|
|
||||||
result, we cache it across sessions using the cache file
|
|
||||||
referenced by `inferior-haskell-module-alist-file'. We test to
|
|
||||||
see if this is newer than `haskell-package-conf-file' every time
|
|
||||||
we load it.
|
|
||||||
|
|
||||||
\(fn SYM)" t nil)
|
|
||||||
|
|
||||||
(autoload 'inf-haskell-mode "inf-haskell" "\
|
|
||||||
Minor mode for enabling inf-haskell process interaction.
|
|
||||||
|
|
||||||
\(fn &optional ARG)" t nil)
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;;;### (autoloads nil nil ("haskell-bot.el" "haskell-checkers.el"
|
|
||||||
;;;;;; "haskell-collapse.el" "haskell-compat.el" "haskell-complete-module.el"
|
|
||||||
;;;;;; "haskell-debug.el" "haskell-mode-pkg.el" "haskell-package.el"
|
|
||||||
;;;;;; "haskell-presentation-mode.el" "haskell-process.el" "haskell-repl.el"
|
|
||||||
;;;;;; "haskell-sandbox.el" "haskell-str.el" "haskell-utils.el"
|
|
||||||
;;;;;; "w3m-haddock.el") (21860 25846 417005 0))
|
|
||||||
|
|
||||||
;;;***
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; End:
|
|
||||||
;;; haskell-mode-autoloads.el ends here
|
|
@@ -1,11 +0,0 @@
|
|||||||
;;; haskell-mode-autoloads.el --- automatically extracted autoloads
|
|
||||||
;;
|
|
||||||
;;; Code:
|
|
||||||
(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
|
|
||||||
|
|
||||||
;; Local Variables:
|
|
||||||
;; version-control: never
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; no-update-autoloads: t
|
|
||||||
;; End:
|
|
||||||
;;; haskell-mode-autoloads.el ends here
|
|
@@ -1,5 +0,0 @@
|
|||||||
(define-package "haskell-mode" "13.12" "A Haskell editing mode"
|
|
||||||
'((cl-lib "0.5")))
|
|
||||||
;; Local Variables:
|
|
||||||
;; no-byte-compile: t
|
|
||||||
;; End:
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,621 +0,0 @@
|
|||||||
This is haskell-mode.info, produced by makeinfo version 5.2 from
|
|
||||||
haskell-mode.texi.
|
|
||||||
|
|
||||||
This manual is for Haskell mode, version @GIT_VERSION@
|
|
||||||
|
|
||||||
Copyright © 2013 Haskell Mode contributors.
|
|
||||||
|
|
||||||
Permission is granted to copy, distribute and/or modify this
|
|
||||||
document under the terms of the GNU Free Documentation License
|
|
||||||
(http://www.gnu.org/licenses/fdl.html), Version 1.3 or any later
|
|
||||||
version published by the Free Software Foundation; with no
|
|
||||||
Invariant Sections, no Front-Cover Texts and no Back-Cover Texts.
|
|
||||||
INFO-DIR-SECTION Emacs
|
|
||||||
START-INFO-DIR-ENTRY
|
|
||||||
* Haskell Mode: (haskell-mode). Haskell Development Environment for Emacs(en)
|
|
||||||
END-INFO-DIR-ENTRY
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Top, Next: Introduction, Up: (dir)
|
|
||||||
|
|
||||||
Haskell Mode
|
|
||||||
************
|
|
||||||
|
|
||||||
Haskell Mode is an Haskell development Environment for GNU Emacs version
|
|
||||||
23 or later. It provides syntax-based indentation, font locking,
|
|
||||||
editing cabal files, and supports running an inferior Haskell
|
|
||||||
interpreter (e.g. GHCi).
|
|
||||||
|
|
||||||
* Menu:
|
|
||||||
|
|
||||||
* Introduction::
|
|
||||||
* Getting Help and Reporting Bugs::
|
|
||||||
* Getting Started::
|
|
||||||
* Editing Haskell Code::
|
|
||||||
* Unicode support::
|
|
||||||
* Indentation::
|
|
||||||
* haskell-decl-scan-mode::
|
|
||||||
* Compilation::
|
|
||||||
* inferior-haskell-mode::
|
|
||||||
* haskell-interactive-mode::
|
|
||||||
* haskell-cabal-mode::
|
|
||||||
* Concept index::
|
|
||||||
* Function index::
|
|
||||||
* Variable index::
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Introduction, Next: Getting Help and Reporting Bugs, Prev: Top, Up: Top
|
|
||||||
|
|
||||||
1 Introduction
|
|
||||||
**************
|
|
||||||
|
|
||||||
"Haskell Mode" is a major mode providing a convenient environment for
|
|
||||||
editing Haskell (http://www.haskell.org) programs.
|
|
||||||
|
|
||||||
Some of its major features are:
|
|
||||||
|
|
||||||
• Syntax highlighting (font lock),
|
|
||||||
• automatic indentation,
|
|
||||||
• on-the-fly documentation,
|
|
||||||
• interaction with inferior GHCi/Hugs instance, and
|
|
||||||
• scanning declarations and placing them in a menu.
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Getting Help and Reporting Bugs, Next: Getting Started, Prev: Introduction, Up: Top
|
|
||||||
|
|
||||||
2 Getting Help and Reporting Bugs
|
|
||||||
*********************************
|
|
||||||
|
|
||||||
This Info manual is work in progress and incomplete. However, you can
|
|
||||||
find more information at these locations in the meantime:
|
|
||||||
|
|
||||||
• Haskell Mode’s GitHub Home
|
|
||||||
(https://github.com/haskell/haskell-mode)
|
|
||||||
• Haskell Wiki Emacs Page
|
|
||||||
(http://www.haskell.org/haskellwiki/Haskell_mode_for_Emacs)
|
|
||||||
|
|
||||||
If you have any questions or like to discuss something regarding
|
|
||||||
Haskell Mode, please consider sending an email to the Haskellmode-emacs
|
|
||||||
mailing list
|
|
||||||
(http://projects.haskell.org/cgi-bin/mailman/listinfo/haskellmode-emacs).
|
|
||||||
The mailing list is also available on Gmane (http://gmane.org/) via the
|
|
||||||
gmane.comp.lang.haskell.emacs
|
|
||||||
(http://dir.gmane.org/gmane.comp.lang.haskell.emacs) newsgroup.
|
|
||||||
|
|
||||||
If you have discovered a bug or wish to request a new feature, you
|
|
||||||
can file a new issue
|
|
||||||
(https://github.com/haskell/haskell-mode/issues/new) with Haskell Mode’s
|
|
||||||
issue tracker. When filing a bug, please state your currently used
|
|
||||||
software version (‘M-x haskell-version’, ‘M-x version’) and what steps
|
|
||||||
to perform in order to reproduce the bug you’re experiencing. Finally,
|
|
||||||
if you happen to be proficient in *note Emacs Lisp: (elisp)Top. you are
|
|
||||||
welcome to submit patches via GitHub Pull Requests
|
|
||||||
(https://help.github.com/articles/using-pull-requests).
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Getting Started, Next: Editing Haskell Code, Prev: Getting Help and Reporting Bugs, Up: Top
|
|
||||||
|
|
||||||
3 Getting Started
|
|
||||||
*****************
|
|
||||||
|
|
||||||
If you are reading this, you have most likely already managed to install
|
|
||||||
Haskell Mode in one way or another. However, just for the record, the
|
|
||||||
officially recommended way is to install Haskell Mode via the Marmalade
|
|
||||||
package archive (http://marmalade-repo.org/packages/haskell-mode) which
|
|
||||||
contains the latest stable release of Haskell Mode.
|
|
||||||
|
|
||||||
Most of Haskell Mode’s settings are configurable via customizable
|
|
||||||
variables (*note (emacs)Easy Customization::, for details). You can use
|
|
||||||
‘M-x haskell-customize’ to browse the ‘haskell’ customization sub-tree.
|
|
||||||
|
|
||||||
One of the important setting you should customize is the
|
|
||||||
‘haskell-mode-hook’ variable (*note (emacs)Hooks::) which gets run right
|
|
||||||
after the ‘haskell-mode’ major mode is initialized for a buffer. You
|
|
||||||
can customize ‘haskell-mode-hook’ by ‘M-x customize-variable <RET>
|
|
||||||
haskell-mode-hook’. It’s highly recommended you set up indentation to
|
|
||||||
match your preferences; *Note Indentation::, for more details about the
|
|
||||||
indentation modes included with Haskell Mode.
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Editing Haskell Code, Next: Unicode support, Prev: Getting Started, Up: Top
|
|
||||||
|
|
||||||
4 Editing Haskell Code
|
|
||||||
**********************
|
|
||||||
|
|
||||||
"Haskell Mode" is actually a collection of so-called major modes(1) one
|
|
||||||
of which is called ‘haskell-mode’. To avoid confusion, when referring
|
|
||||||
to this package the name “Haskell mode” is written in a normal font,
|
|
||||||
whereas when referring the major mode of the same name ‘haskell-mode’
|
|
||||||
written with a dash in-between in a typewriter font is used.
|
|
||||||
|
|
||||||
As one might guess, ‘haskell-mode’ is the (programming language(2))
|
|
||||||
major mode for editing (non-literate) Haskell source code.
|
|
||||||
‘haskell-mode’ is associated with the file extensions listed below by
|
|
||||||
default(3).
|
|
||||||
|
|
||||||
‘.hs’
|
|
||||||
official file extension for (non-literate) Haskell 98/2010 files
|
|
||||||
‘.hsc’
|
|
||||||
“almost-Haskell” input file for the hsc2hs
|
|
||||||
(http://www.haskell.org/ghc/docs/latest/html/users_guide/hsc2hs.html)
|
|
||||||
pre-processor
|
|
||||||
‘.cpphs’
|
|
||||||
input file for the cpphs (http://projects.haskell.org/cpphs/)
|
|
||||||
pre-processor
|
|
||||||
|
|
||||||
The major mode ‘literate-haskell-mode’ (which is derived from
|
|
||||||
‘haskell-mode’ and thus transitively from ‘prog-mode’) provides support
|
|
||||||
for literate Haskell programs
|
|
||||||
(http://www.haskell.org/haskellwiki/Literate_programming) and is
|
|
||||||
associated with the ‘.lhs’ file extension by default.
|
|
||||||
|
|
||||||
‘literate-haskell-mode’ supports Bird-style as well as TeX-style
|
|
||||||
literate Haskell files. The currently detected literate Haskell variant
|
|
||||||
is shown in the mode line (*note (emacs)Mode Line::) as either
|
|
||||||
‘LitHaskell/bird’ or ‘LitHaskell/tex’.
|
|
||||||
|
|
||||||
4.1 Font Lock Support
|
|
||||||
=====================
|
|
||||||
|
|
||||||
‘haskell-mode’ supports "syntax highlighting" via Emacs’ Font Lock minor
|
|
||||||
mode which should be enabled by default in current Emacsen. *Note
|
|
||||||
(emacs)Font Lock::, for more information on how to control
|
|
||||||
‘font-lock-mode’.
|
|
||||||
|
|
||||||
---------- Footnotes ----------
|
|
||||||
|
|
||||||
(1) for more information about the concept of "major modes" *note
|
|
||||||
(emacs)Major Modes::
|
|
||||||
|
|
||||||
(2) ‘haskell-mode’ is derived from ‘prog-mode’
|
|
||||||
|
|
||||||
(3) for more information about file associations, *note
|
|
||||||
(emacs)Choosing Modes::
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Unicode support, Next: Indentation, Prev: Editing Haskell Code, Up: Top
|
|
||||||
|
|
||||||
5 Unicode support
|
|
||||||
*****************
|
|
||||||
|
|
||||||
See the Haskell Wiki’s entry on Unicode Symbols
|
|
||||||
(http://www.haskell.org/haskellwiki/Unicode-symbols) for general
|
|
||||||
information about Unicode support in Haskell.
|
|
||||||
|
|
||||||
As Emacs supports editing files containing Unicode out of the box, so
|
|
||||||
does Haskell Mode. As an add-on, Haskell Mode includes the
|
|
||||||
‘haskell-unicode’ input method which allows you to easily type a number
|
|
||||||
of Unicode symbols that are useful when writing Haskell code; *Note
|
|
||||||
(emacs)Input Methods::, for more details.
|
|
||||||
|
|
||||||
To automatically enable the ‘haskell-unicode’ input method in
|
|
||||||
haskell-mode buffers use ‘M-x customize-variable <RET>
|
|
||||||
haskell-mode-hook’ or put the following code in your ‘.emacs’ file:
|
|
||||||
|
|
||||||
(add-hook 'haskell-mode-hook 'turn-on-haskell-unicode-input-method)
|
|
||||||
|
|
||||||
To temporarily enable this input method for a single buffer you can use
|
|
||||||
‘M-x turn-on-haskell-unicode-input-method’.
|
|
||||||
|
|
||||||
When the ‘haskell-unicode’ input method is active, you can simply
|
|
||||||
type ‘->’ and it is immediately replaced with ‘→’. Use ‘C-\’ to toggle
|
|
||||||
the input method. To see a table of all key sequences use ‘M-x
|
|
||||||
describe-input-method <RET> haskell-unicode’. A sequence like ‘<=’ is
|
|
||||||
ambiguous and can mean either ‘⇐’ or ‘≤’. Typing it presents you with a
|
|
||||||
choice. Type ‘1’ or ‘2’ to select an option or keep typing to use the
|
|
||||||
default option.
|
|
||||||
|
|
||||||
If you don’t like the highlighting of partially matching tokens you
|
|
||||||
can turn it off by setting ‘input-method-highlight-flag’ to ‘nil’ via
|
|
||||||
‘M-x customize-variable’.
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Indentation, Next: haskell-decl-scan-mode, Prev: Unicode support, Up: Top
|
|
||||||
|
|
||||||
6 Indentation
|
|
||||||
*************
|
|
||||||
|
|
||||||
For general information about indentation support in GNU Emacs, *note
|
|
||||||
(emacs)Indentation::.
|
|
||||||
|
|
||||||
In Haskell, code indentation has semantic meaning as it defines the
|
|
||||||
block structure(1).
|
|
||||||
|
|
||||||
As GNU Emacs’ default indentation function (i.e. ‘indent-relative’)
|
|
||||||
is not designed for use with Haskell’s layout rule, Haskell mode
|
|
||||||
includes three different indentation minor modes with different
|
|
||||||
trade-offs:
|
|
||||||
|
|
||||||
‘turn-on-haskell-simple-indent’
|
|
||||||
|
|
||||||
A very simple indentation scheme; In this scheme, <TAB> will now
|
|
||||||
move the cursor to the next indent point in the previous non-blank
|
|
||||||
line. An indent point is a non-whitespace character following
|
|
||||||
whitespace.
|
|
||||||
|
|
||||||
‘turn-on-haskell-indent’
|
|
||||||
|
|
||||||
Intelligent semi-automatic indentation for Haskell’s layout rule.
|
|
||||||
The basic idea is to have <TAB> cycle through possibilities
|
|
||||||
indentation points based on some clever heuristics.
|
|
||||||
|
|
||||||
The rationale and the implementation principles are described in
|
|
||||||
more detail in the article ‘Dynamic tabbing for automatic
|
|
||||||
indentation with the layout rule’ published in the Journal of
|
|
||||||
Functional Programming 8.5 (1998).
|
|
||||||
|
|
||||||
‘turn-on-haskell-indentation’
|
|
||||||
|
|
||||||
Improved variation of ‘turn-on-haskell-indent’ indentation mode.
|
|
||||||
Rebinds <RET> and <DEL>, so that indentations can be set and
|
|
||||||
deleted as if they were real tabs.
|
|
||||||
|
|
||||||
To enable one of these three mutually exclusive indentation schemes,
|
|
||||||
you just need call one (and only one!) of the ‘turn-on-*’ commands
|
|
||||||
while in the buffer you want the indentation scheme to be activated for.
|
|
||||||
|
|
||||||
The recommended way is to add one of ‘turn-on-*’ commands to
|
|
||||||
‘haskell-mode-hook’. This can be done either by using ‘M-x
|
|
||||||
customize-variable <RET> haskell-mode-hook’ which provides a convenient
|
|
||||||
user interface or by adding _one_ of the following three lines to your
|
|
||||||
‘.emacs’ file:
|
|
||||||
|
|
||||||
(add-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)
|
|
||||||
(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
|
|
||||||
(add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
|
|
||||||
|
|
||||||
6.1 Interactive Block Indentation
|
|
||||||
=================================
|
|
||||||
|
|
||||||
By inserting the key bindings for ‘C-,’ and ‘C-.’ (these bindings are
|
|
||||||
convenient on keyboard layouts where <,> and <.> are adjacent keys) as
|
|
||||||
shown below you can interactively de/indent either the following nested
|
|
||||||
block or, if a region is active while in Transient Mark Mode (*note
|
|
||||||
(emacs)Disabled Transient Mark::), de/indent the active region.
|
|
||||||
|
|
||||||
By using a numeric prefix argument (*note (elisp)Prefix Command
|
|
||||||
Arguments::) you can modify the shift-amount; for instance, ‘C-u C-,’
|
|
||||||
increases indentation by 4 characters at once.
|
|
||||||
|
|
||||||
(eval-after-load "haskell-mode"
|
|
||||||
'(progn
|
|
||||||
(define-key haskell-mode-map (kbd "C-,") 'haskell-move-nested-left)
|
|
||||||
(define-key haskell-mode-map (kbd "C-.") 'haskell-move-nested-right)))
|
|
||||||
|
|
||||||
6.2 Rectangle Commands
|
|
||||||
======================
|
|
||||||
|
|
||||||
GNU Emacs provides so-called "rectangle commands" which operate on
|
|
||||||
rectangular areas of text, which are particularly useful for languages
|
|
||||||
with a layout rule such as Haskell. *Note (emacs)Rectangles::, to learn
|
|
||||||
more about rectangle commands.
|
|
||||||
|
|
||||||
Moreover, CUA mode (*note (emacs)CUA Bindings::) provides enhanced
|
|
||||||
rectangle support with visible rectangle highlighting. When CUA mode is
|
|
||||||
active, you can initiate a rectangle selection by ‘C-RET’ and extend it
|
|
||||||
simply by movement commands. You don’t have to enable full CUA mode to
|
|
||||||
benefit from these enhanced rectangle commands; you can activate CUA
|
|
||||||
selection mode (without redefining ‘C-x’,‘C-c’,‘C-v’, and ‘C-z’) by
|
|
||||||
calling ‘M-x cua-selection-mode’ (or adding ‘(cua-selection-mode nil)’
|
|
||||||
to your ‘haskell-mode-hook’).
|
|
||||||
|
|
||||||
---------- Footnotes ----------
|
|
||||||
|
|
||||||
(1) Haskell also supports braces and semicolons notation for
|
|
||||||
conveying the block structure. However, most Haskell programs written
|
|
||||||
by humans use indentation for block structuring.
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: haskell-decl-scan-mode, Next: Compilation, Prev: Indentation, Up: Top
|
|
||||||
|
|
||||||
7 ‘haskell-decl-scan-mode’
|
|
||||||
**************************
|
|
||||||
|
|
||||||
‘haskell-decl-scan-mode’ is a minor mode which performs declaration
|
|
||||||
scanning and provides ‘M-x imenu’ support (*note (emacs)Imenu:: for more
|
|
||||||
information).
|
|
||||||
|
|
||||||
For non-literate and TeX-style literate scripts, the common
|
|
||||||
convention that top-level declarations start at the first column is
|
|
||||||
assumed. For Bird-style literate scripts, the common convention that
|
|
||||||
top-level declarations start at the third column, ie. after ‘> ’, is
|
|
||||||
assumed.
|
|
||||||
|
|
||||||
When ‘haskell-decl-scan-mode’ is active, the standard Emacs top-level
|
|
||||||
definition movement commands (*note (emacs)Moving by Defuns::) are
|
|
||||||
enabled to operate on Haskell declarations:
|
|
||||||
|
|
||||||
‘C-M-a’
|
|
||||||
Move to beginning of current or preceding declaration
|
|
||||||
(‘beginning-of-defun’).
|
|
||||||
|
|
||||||
‘C-M-e’
|
|
||||||
Move to end of current or following declaration (‘end-of-defun’).
|
|
||||||
|
|
||||||
‘C-M-h’
|
|
||||||
Select whole current or following declaration (‘mark-defun’).
|
|
||||||
|
|
||||||
Moreover, if enabled via the option
|
|
||||||
‘haskell-decl-scan-add-to-menubar’, a menu item “Declarations” is added
|
|
||||||
to the menu bar listing the scanned declarations and allowing to jump to
|
|
||||||
declarations in the source buffer.
|
|
||||||
|
|
||||||
It’s recommended to have font lock mode enabled (*note (emacs)Font
|
|
||||||
Lock::) as ‘haskell-decl-scan-mode’ ignores text highlighted with
|
|
||||||
‘font-lock-comment-face’.
|
|
||||||
|
|
||||||
As usual, in order to activate ‘haskell-decl-scan-mode’ automatically
|
|
||||||
for Haskell buffers, add ‘turn-on-haskell-decl-scan’ to
|
|
||||||
‘haskell-mode-hook’:
|
|
||||||
|
|
||||||
(add-hook 'haskell-mode-hook 'turn-on-haskell-decl-scan)
|
|
||||||
|
|
||||||
‘haskell-decl-scan-mode’ enables the use of features that build upon
|
|
||||||
‘imenu’ support such as Speedbar Frames (*note (emacs)Speedbar::) or the
|
|
||||||
global “Which Function” minor mode (*note (emacs)Which Function::).
|
|
||||||
|
|
||||||
In order to enable ‘which-function-mode’ for Haskell buffers you need
|
|
||||||
to add the following to your Emacs initialization:
|
|
||||||
|
|
||||||
(eval-after-load "which-func"
|
|
||||||
'(add-to-list 'which-func-modes 'haskell-mode))
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Compilation, Next: inferior-haskell-mode, Prev: haskell-decl-scan-mode, Up: Top
|
|
||||||
|
|
||||||
8 Compilation
|
|
||||||
*************
|
|
||||||
|
|
||||||
Haskell mode comes equipped with a specialized "Compilation mode"
|
|
||||||
tailored to GHC’s compiler messages with optional support for Cabal
|
|
||||||
projects. *Note (emacs)Compilation Mode::, for more information about
|
|
||||||
the basic commands provided by the Compilation mode which are available
|
|
||||||
in the Haskell compilation sub-mode as well. The additional features
|
|
||||||
provided compared to Emacs’ basic Compilation mode are:
|
|
||||||
|
|
||||||
• DWIM-style auto-detection of compile command (including support for
|
|
||||||
CABAL projects)
|
|
||||||
• Support for GHC’s compile messages and recognizing error, warning
|
|
||||||
and info source locations (including ‘-ferror-spans’ syntax)
|
|
||||||
• Support for filtering out GHC’s uninteresting ‘Loading package...’
|
|
||||||
linker messages
|
|
||||||
|
|
||||||
In order to use it, invoke the ‘haskell-compile’ command instead of
|
|
||||||
‘compile’ as you would for the ordinary Compilation mode. It’s
|
|
||||||
recommended to bind ‘haskell-compile’ to a convenient key binding. For
|
|
||||||
instance, you can add the following to your Emacs initialization to bind
|
|
||||||
‘haskell-compile’ to ‘C-c C-c’.
|
|
||||||
|
|
||||||
(eval-after-load "haskell-mode"
|
|
||||||
'(define-key haskell-mode-map (kbd "C-c C-c") 'haskell-compile))
|
|
||||||
|
|
||||||
(eval-after-load "haskell-cabal"
|
|
||||||
'(define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-compile))
|
|
||||||
|
|
||||||
The following description assumes that ‘haskell-compile’ has been bound
|
|
||||||
to ‘C-c C-c’.
|
|
||||||
|
|
||||||
When invoked, ‘haskell-compile’ tries to guess how to compile the
|
|
||||||
Haskell program your currently visited buffer belongs to, by searching
|
|
||||||
for a ‘.cabal’ file in the current of enclosing parent folders. If a
|
|
||||||
‘.cabal’ file was found, the command defined in the
|
|
||||||
‘haskell-compile-cabal-build-command’ option is used. Moreover, when
|
|
||||||
requesting to compile a ‘.cabal’-file is detected and a negative prefix
|
|
||||||
argument (e.g. ‘C-- C-c C-c’) was given, the alternative
|
|
||||||
‘haskell-compile-cabal-build-command-alt’ is invoked. By default,
|
|
||||||
‘haskell-compile-cabal-build-command-alt’ contains a ‘cabal clean -s’
|
|
||||||
command in order to force a full rebuild.
|
|
||||||
|
|
||||||
Otherwise if no ‘.cabal’ could be found, a single-module compilation
|
|
||||||
is assumed and ‘haskell-compile-command’ is used (_if_ the currently
|
|
||||||
visited buffer contains Haskell source code).
|
|
||||||
|
|
||||||
You can also inspect and modify the compile command to be invoked
|
|
||||||
temporarily by invoking ‘haskell-compile’ with a prefix argument (e.g.
|
|
||||||
‘C-u C-c C-c’). If later-on you want to recompile using the same
|
|
||||||
customized compile command, invoke ‘recompile’ (bound to ‘g’) inside the
|
|
||||||
‘*haskell-compilation*’ buffer.
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: inferior-haskell-mode, Next: haskell-interactive-mode, Prev: Compilation, Up: Top
|
|
||||||
|
|
||||||
9 ‘inferior-haskell-mode’
|
|
||||||
*************************
|
|
||||||
|
|
||||||
The major mode ‘inferior-haskell-mode’ provides support for interacting
|
|
||||||
with an inferior Haskell process based on ‘comint-mode’.
|
|
||||||
|
|
||||||
By default the ‘haskell-mode-map’ keymap is setup to use this mode:
|
|
||||||
|
|
||||||
‘C-c C-z’
|
|
||||||
is bound to ‘switch-to-haskell’
|
|
||||||
‘C-c C-b’
|
|
||||||
is bound to ‘switch-to-haskell’
|
|
||||||
‘C-c C-l’
|
|
||||||
is bound to ‘inferior-haskell-load-file’
|
|
||||||
‘C-c C-t’
|
|
||||||
is bound to ‘inferior-haskell-type’
|
|
||||||
‘C-c C-i’
|
|
||||||
is bound to ‘inferior-haskell-info’
|
|
||||||
|
|
||||||
The Haskell interpreter used by the inferior Haskell mode is
|
|
||||||
auto-detected by default, but is customizable via the
|
|
||||||
‘haskell-program-name’ variable.
|
|
||||||
|
|
||||||
Currently, GHCi and Hugs are support as Haskell interpreter.
|
|
||||||
|
|
||||||
TODO/WRITEME
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: haskell-interactive-mode, Next: haskell-cabal-mode, Prev: inferior-haskell-mode, Up: Top
|
|
||||||
|
|
||||||
10 ‘haskell-interactive-mode’
|
|
||||||
*****************************
|
|
||||||
|
|
||||||
An alternative mode providing a REPL (read–eval–print loop) via GHCi
|
|
||||||
sessions is called ‘haskell-interactive-mode’, which effectively
|
|
||||||
replaces ‘inferior-haskell-mode’, but comes with a different set of
|
|
||||||
features:
|
|
||||||
|
|
||||||
• Separate sessions per Cabal project ‘haskell-session.el’.
|
|
||||||
• A new inferior Haskell process handling code ‘haskell-process.el’.
|
|
||||||
• New REPL implementation similiar to SLIME/IELM
|
|
||||||
‘haskell-interactive-mode.el’.
|
|
||||||
|
|
||||||
In order to use ‘haskell-interactive-mode’ instead of the default
|
|
||||||
‘inferior-haskell-mode’, you need to replace some of the default
|
|
||||||
keybindings in the ‘haskell-mode-map’ keymap with the respective
|
|
||||||
‘haskell-interactive-mode’ counterparts:
|
|
||||||
|
|
||||||
(eval-after-load "haskell-mode"
|
|
||||||
'(progn
|
|
||||||
(define-key haskell-mode-map (kbd "C-x C-d") nil)
|
|
||||||
(define-key haskell-mode-map (kbd "C-c C-z") 'haskell-interactive-switch)
|
|
||||||
(define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-file)
|
|
||||||
(define-key haskell-mode-map (kbd "C-c C-b") 'haskell-interactive-switch)
|
|
||||||
(define-key haskell-mode-map (kbd "C-c C-t") 'haskell-process-do-type)
|
|
||||||
(define-key haskell-mode-map (kbd "C-c C-i") 'haskell-process-do-info)
|
|
||||||
(define-key haskell-mode-map (kbd "C-c M-.") nil)
|
|
||||||
(define-key haskell-mode-map (kbd "C-c C-d") nil)))
|
|
||||||
|
|
||||||
With ‘haskell-interactive-mode’, each Haskell source buffer is
|
|
||||||
associated with at most one GHCi session, so when you call
|
|
||||||
‘haskell-process-load-file’ for a Haskell source buffer which has no
|
|
||||||
session associated yet, you’re asked which GHCi session to create or
|
|
||||||
associate with.
|
|
||||||
|
|
||||||
TODO/WRITEME
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: haskell-cabal-mode, Next: Concept index, Prev: haskell-interactive-mode, Up: Top
|
|
||||||
|
|
||||||
11 ‘haskell-cabal-mode’
|
|
||||||
***********************
|
|
||||||
|
|
||||||
‘haskell-cabal-mode’ is a major mode for editing Cabal package
|
|
||||||
description files
|
|
||||||
(http://www.haskell.org/cabal/users-guide/developing-packages.html) and
|
|
||||||
is automatically associated with files having a ‘.cabal’ extension.
|
|
||||||
|
|
||||||
For quickly locating and jumping to the nearest ‘.cabal’ file from a
|
|
||||||
Haskell source buffer, you can use ‘M-x haskell-cabal-visit-file’; with
|
|
||||||
a prefix argument (i.e. ‘C-u’) ‘find-file-other-window’ is used to
|
|
||||||
visit the ‘.cabal’ file. If you wish, you can bind
|
|
||||||
‘haskell-cabal-visit-file’ to a convenient key sequence, e.g.
|
|
||||||
|
|
||||||
(eval-after-load "haskell-mode"
|
|
||||||
(define-key haskell-mode-map (kbd "C-c v c") 'haskell-cabal-visit-file))
|
|
||||||
|
|
||||||
TODO/WRITEME
|
|
||||||
|
|
||||||
|
|
||||||
File: haskell-mode.info, Node: Concept index, Next: Function index, Prev: haskell-cabal-mode, Up: Top
|
|
||||||
|
|
||||||
Concept index
|
|
||||||
*************
|
|
||||||
|
|
||||||
|