%% %% This is file `langsci-avm.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% langsci-avm.dtx (with options: `package') %% ------------------------------------------------------------------------------ %% %% langsci-avm is aimed at typesetting beautiful feature structures, %% also known as attribute-value matrices (AVMs), for use in linguistics. %% %% The package provides a minimal and easy to read syntax. %% It depends only on the array package and can be placed almost everywhere, %% in particular in footnotes or graphs and tree structures. The package is meant %% as an update to, and serves the same purpose as, Christopher Manning’s %% avm package, but shares no code base with that package. %% %% langsci-avm was developed at Language Science Press to help in the %% production of scientific texts in linguistics. %% %% Copyright (C) 2020 by Felix Kopecky, Language Science Press %% %% This work consists of the file langsci-avm.dtx %% and the derived files langsci-avm.ins, %% langsci-avm.pdf. %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this %% license or (at your option) any later version. The latest version %% of this license is at . %% %% This work is ``maintained'' (per LPPL maintenance status) by %% Felix Kopecky . %% %% The development version can be found at %% %% https://github.com/langsci/langsci-avm %% %% for those people who are interested. Pull requests are welcome. %% %% Please report any bugs or feature requests to %% %% https://github.com/langsci/langsci-avm/issues %% %% ------------------------------------------------------------------------------ \RequirePackage{xparse,array} \ProvidesExplPackage {langsci-avm} {2020-07-15} {0.2.1} {AVMs and feature structures in LaTeX3} \NewDocumentCommand{\avm}{ O{} +m } { \c_group_begin_token \__avm_initialise_document_commands: \__avm_initialise_custom_commands: \tl_use:N \l__avm_defined_commands_tl \bool_set_true:N \l__avm_mode_bool \keys_set:nn { avm } { #1 } \__avm_wrap:n { #2 } \c_group_end_token } \NewDocumentCommand{\avmsetup}{ m } { \keys_set:nn { avm } { #1 } } \keys_define:nn { avm } { stretch .tl_set:N = \l__avm_arraystretch_tl, stretch .initial:n = {0.9}, columnsep .dim_set:N = \l__avm_tabcolsep_dim, columnsep .initial:n = {.5ex}, delimfactor .int_set:N = \l__avm_delimfactor_int, delimfactor .initial:n = {1000}, delimfall .dim_set:N = \l__avm_delimshortfall_dim, delimfall .initial:n = {0pt}, attributes .code:n = {\cs_set:Nn \__avm_font_attribute: {#1}}, attributes .initial:n = {\scshape}, types .code:n = {\cs_set:Nn \__avm_font_type: {#1}}, types .initial:n = {\itshape}, values .code:n = {\cs_set:Nn \__avm_font_value: {#1}}, values .initial:n = {\itshape}, tags .code:n = {\cs_set:Nn \__avm_font_tag: {#1}}, tags .initial:n = {\footnotesize}, apptovalues .code:n = {\cs_set:Nn \__avm_deinit_second_column: {#1}}, apptovalues .initial:n = {\/}, singleton .code:n = {\cs_set:Nn \__avm_font_singleton: {#1}}, singleton .initial:n = {\normalfont}, switch .code:n = {\tl_set:Nn \__avm_mode_switch_character {#1}}, switch .initial:n = { ! }, extraskip .dim_set:N = \l__avm_extra_skip_dim, extraskip .initial:n = {\smallskipamount}, customise .code:n = {\cs_set:Nn \__avm_initialise_custom_commands: {#1}}, customise .initial:n = { }, style .choice:, style / narrow .code:n = {\delimiterfactor=997\delimitershortfall5pt}, } \NewDocumentCommand{\avmdefinestyle}{ m m } { \keys_define:nn { avm } { style / #1 .code:n = { \keys_set:nn { avm } { #2 } } } } \NewDocumentCommand{\avmdefinecommand}{ m O{} m } { \tl_put_right:Nn \l__avm_defined_commands_tl { \exp_args:Nc \DeclareDocumentCommand { #1 } { s } { #2 \IfBooleanF { ##1 } { & } \avmsetup{ #3 } } } } \bool_new:N \l__avm_mode_bool \seq_new:N \l__avm_parens_tracker \tl_new:N \l__avm_defined_commands_tl \cs_generate_variant:Nn \seq_set_split:Nnn { NVn } \bool_new:N \l__avm_in_first_column \cs_new:Nn \__avm_init_first_column: { \bool_set_true:N \l__avm_in_first_column \normalfont\__avm_font_attribute: } \cs_new:Nn \__avm_init_second_column: { \bool_set_false:N \l__avm_in_first_column \normalfont\__avm_font_value: } \cs_new:Nn \__avm_kern_unused_columns: { \bool_if:NTF \l__avm_in_first_column { \span\hspace*{-2\tabcolsep} } { } } \cs_new:Nn \__avm_extra_skip: { \peek_meaning_ignore_spaces:NTF \\ {\vspace*{\l__avm_extra_skip_dim}} {} } \cs_new:Nn \__avm_module_begin: { \begin{tabular}{@{} >{\__avm_init_first_column:}l >{\__avm_init_second_column:}l <{\__avm_deinit_second_column:} @{}} } \cs_new:Nn \__avm_module_end: { \__avm_kern_unused_columns: \end{tabular} } \cs_new:Nn \__avm_replace_lbrace: { \__avm_parse_output:nw { \c_math_toggle_token\left\lbrace\__avm_module_begin: } } \cs_new:Nn \__avm_replace_rbrace: { \__avm_parse_output:nw { \__avm_module_end:\right\rbrace\c_math_toggle_token\__avm_extra_skip: } } \cs_new:Nn \__avm_replace_lbrack: { \__avm_parse_output:nw { \c_math_toggle_token\left\lbrack\__avm_module_begin: } } \cs_new:Nn \__avm_replace_rbrack: { \__avm_parse_output:nw { \__avm_module_end:\right\rbrack\c_math_toggle_token\__avm_extra_skip: } } \cs_new:Nn \__avm_replace_lparen: { \__avm_parse_output:nw { \c_math_toggle_token\left(\__avm_module_begin: } } \cs_new:Nn \__avm_replace_rparen: { \__avm_parse_output:nw { \__avm_module_end:\right)\c_math_toggle_token\__avm_extra_skip: } } \cs_new:Nn \__avm_replace_langle: { \__avm_parse_output:nw { \c_math_toggle_token\left<\__avm_module_begin: } } \cs_new:Nn \__avm_replace_rangle: { \__avm_parse_output:nw { \__avm_module_end:\right>\c_math_toggle_token\__avm_extra_skip: } } \cs_new:Nn \__avm_replace_plus: { \__avm_parse_output:nw { \ensuremath { \oplus \! } } } \cs_new:Nn \__avm_replace_minus: { \__avm_parse_output:nw { \ensuremath { \ominus \! } } } \cs_new:Nn \__avm_replace_circle: { \__avm_parse_output:nw { \ensuremath { \bigcirc \, } } } \cs_new:Npn \__avm_controls_tag:n #1 { \fboxsep.25ex\fbox{\normalfont\__avm_font_tag: #1} } \cs_new:Npn \__avm_controls_type:n #1 { \c_group_begin_token\normalfont\__avm_font_type: #1\c_group_end_token } \cs_new_protected:Npn \__avm_controls_type_starred:n #1 { \bool_set_false:N \l__avm_in_first_column \normalfont\__avm_font_type: #1 \__avm_deinit_second_column:\span\hspace*{-2\tabcolsep} \peek_meaning_ignore_spaces:NTF \\ {} {\\} } \cs_new_protected:Npn \__avm_controls_punk:nn #1 #2 { \bool_set_false:N \l__avm_in_first_column \normalfont\c_group_begin_token\__avm_font_attribute:#1% \c_group_end_token\hspace{2\tabcolsep}% \c_group_begin_token\__avm_font_type: #2\c_group_end_token% \__avm_deinit_second_column:\span\hspace*{-2\tabcolsep} \peek_meaning_ignore_spaces:NTF \\ {} {\\} } \cs_new:Nn \__avm_initialise_document_commands: { \def\arraystretch{\tl_use:N \l__avm_arraystretch_tl} \tabcolsep=\l__avm_tabcolsep_dim \delimiterfactor=\l__avm_delimfactor_int \delimitershortfall=\l__avm_delimshortfall_dim \cs_if_exist:NTF \tag { \RenewDocumentCommand{\tag}{m}{ \__avm_controls_tag:n {##1} } } { \NewDocumentCommand{\tag}{m}{ \__avm_controls_tag:n {##1} } } \cs_if_exist:NTF \0 { \RenewDocumentCommand{\0}{}{ \__avm_controls_tag:n {0} } } { \NewDocumentCommand{\0}{}{ \__avm_controls_tag:n {0} } } \cs_if_exist:NTF \1 { \RenewDocumentCommand{\1}{}{ \__avm_controls_tag:n {1} } } { \NewDocumentCommand{\1}{}{ \__avm_controls_tag:n {1} } } \cs_if_exist:NTF \2 { \RenewDocumentCommand{\2}{}{ \__avm_controls_tag:n {2} } } { \NewDocumentCommand{\2}{}{ \__avm_controls_tag:n {2} } } \cs_if_exist:NTF \3 { \RenewDocumentCommand{\3}{}{ \__avm_controls_tag:n {3} } } { \NewDocumentCommand{\3}{}{ \__avm_controls_tag:n {3} } } \cs_if_exist:NTF \4 { \RenewDocumentCommand{\4}{}{ \__avm_controls_tag:n {4} } } { \NewDocumentCommand{\4}{}{ \__avm_controls_tag:n {4} } } \cs_if_exist:NTF \5 { \RenewDocumentCommand{\5}{}{ \__avm_controls_tag:n {5} } } { \NewDocumentCommand{\5}{}{ \__avm_controls_tag:n {5} } } \cs_if_exist:NTF \6 { \RenewDocumentCommand{\6}{}{ \__avm_controls_tag:n {6} } } { \NewDocumentCommand{\6}{}{ \__avm_controls_tag:n {6} } } \cs_if_exist:NTF \7 { \RenewDocumentCommand{\7}{}{ \__avm_controls_tag:n {7} } } { \NewDocumentCommand{\7}{}{ \__avm_controls_tag:n {7} } } \cs_if_exist:NTF \8 { \RenewDocumentCommand{\8}{}{ \__avm_controls_tag:n {8} } } { \NewDocumentCommand{\8}{}{ \__avm_controls_tag:n {8} } } \cs_if_exist:NTF \9 { \RenewDocumentCommand{\9}{}{ \__avm_controls_tag:n {9} } } { \NewDocumentCommand{\9}{}{ \__avm_controls_tag:n {9} } } \cs_if_exist:NTF \type { \RenewDocumentCommand{\type}{s m} { \IfBooleanTF { ##1 } { \__avm_controls_type_starred:n {##2} } { \__avm_controls_type:n {##2} } } } { \NewDocumentCommand{\type}{s m} { \IfBooleanTF { ##1 } { \__avm_controls_type_starred:n {##2} } { \__avm_controls_type:n {##2} } } } \cs_if_exist:NTF \punk { \RenewDocumentCommand{\punk}{m m} { \__avm_controls_punk:nn {##1}{##2} } } { \NewDocumentCommand{\punk}{m m} { \__avm_controls_punk:nn {##1}{##2} } } } \cs_new_protected:Npn \__avm_wrap:n #1 { \seq_set_split:NVn \l__avm_wrapper_seq \__avm_mode_switch_character { #1 } \seq_map_inline:Nn \l__avm_wrapper_seq { \exp_args:No \exp_not:o { \__avm_parse:n {##1} } \bool_set_inverse:N \l__avm_mode_bool } } \cs_new:Npn \__avm_parse:n #1 { \exp:w \group_align_safe_begin: \__avm_parse_loop:w #1 \q_recursion_tail \q_recursion_stop \__avm_result:n { } } \cs_new:Npn \__avm_end:w \__avm_result:n #1 { \group_align_safe_end: \exp_end: #1 } \cs_new:Npn \__avm_parse_loop:w #1 \q_recursion_stop { \tl_if_head_is_N_type:nTF {#1} { \__avm_N_type:N #1 \q_recursion_stop } { \tl_if_head_is_group:nTF {#1} { \__avm_replace_group:nw #1 \q_recursion_stop } { \__avm_replace_space:w #1 \q_recursion_stop } } } \cs_new:Npn \__avm_N_type:N #1 { \quark_if_recursion_tail_stop_do:Nn #1 { \__avm_end:w } \bool_if:NTF \l__avm_mode_bool { \__avm_replace:N #1 } { \__avm_replace_none:N #1 } } \cs_new:Npn \__avm_replace_none:N #1 { \__avm_parse_output:nw {#1} } \cs_new:Npn \__avm_replace:N #1 { \str_case:nnF {#1} { { \+ }{ \__avm_replace_plus: } { \- }{ \__avm_replace_minus: } { \shuffle }{ \__avm_replace_circle: } { [ }{ \__avm_replace_lbrack: } { ] }{ \__avm_replace_rbrack: } { ( }{ \__avm_replace_lparen: } { ) }{ \__avm_replace_rparen: } { \{ }{ \__avm_replace_lbrace: } { \} }{ \__avm_replace_rbrace: } { < }{ \__avm_replace_langle: } { > }{ \__avm_replace_rangle: } } { \__avm_replace_none:N #1 } } \cs_new:Npn \__avm_replace_group:nw #1 { \exp_args:NNo \exp_args:No \__avm_replace_group:n { \__avm_parse:n {#1} } } \cs_new:Npn \__avm_replace_group:n #1 { \__avm_parse_output:nw { {#1} } } \exp_last_unbraced:NNo \cs_new:Npn \__avm_replace_space:w \c_space_tl { \__avm_parse_output:nw { ~ } } \cs_new:Npn \__avm_parse_output:nw #1 #2 \q_recursion_stop \__avm_result:n #3 { \__avm_parse_loop:w #2 \q_recursion_stop \__avm_result:n {#3 #1 } } %% %% %% End of file `langsci-avm.sty'.