mirror of https://gitlab.com/QEF/q-e.git
509 lines
15 KiB
Tcl
509 lines
15 KiB
Tcl
#
|
|
# This file is sourced by "gen-emacs-mode" script and contains the
|
|
# machinery for generating the Emacs major mode files for Quantum
|
|
# ESPRESSO. It relies heavily on: (1) helpdoc utility, (2) INPUT_*.def
|
|
# files, and (3) templates provided in ../GUI/QE-modes/qe-modes.templates/ directory.
|
|
#
|
|
|
|
###
|
|
# Purpose: extract the module name from INPUT_*.def filename
|
|
proc ::helpdoc::modulename_from_defname {deffile} {
|
|
|
|
# strip the path from $deffile
|
|
|
|
set def_file [file tail $deffile]
|
|
|
|
# the module-name of INPUT_XX.def is [string tolower XX]
|
|
|
|
return [string tolower [regsub {^INPUT_} [file rootname $def_file] {}]]
|
|
}
|
|
|
|
# Purpose: quote the list elements, i.e., transform {a b c} to either {"a" "b" "c"},
|
|
# or {"${prefix}a" "${prefix}b" "${prefix}c"} if $prefix != ""
|
|
#
|
|
# prefix = optional argument (default = "")
|
|
proc ::helpdoc::quote_list {lst {prefix {}}} {
|
|
set result ""
|
|
foreach item $lst {
|
|
append result "\"${prefix}$item\" "
|
|
}
|
|
return $result
|
|
}
|
|
|
|
|
|
# Purpose: transform the QE flags list {alat | bohr | angstroms} to emacs list {"alat" "bohr" "angstroms"}
|
|
proc ::helpdoc::flags_to_elist {flags} {
|
|
foreach f [regsub -all {\|} $flags { }] {
|
|
append res "\"$f\" "
|
|
}
|
|
return $res
|
|
}
|
|
|
|
# Purpose: store the namelists, variables, cards, etc. that are stated in the def file
|
|
# (this proc is used by tree's walkproc method; see qe_mode_process_def)
|
|
proc ::helpdoc::getFontlockKeys {tree node action} {
|
|
variable arr
|
|
variable inside_namelist
|
|
variable fontlock
|
|
variable defun
|
|
variable module
|
|
|
|
set tag [$tree get $node tag]
|
|
set attr [getFromTree $tree $node attributes]
|
|
|
|
catch {unset arr}
|
|
attr2array_ arr $attr
|
|
set name [arr name]
|
|
|
|
if { $action == "enter" } {
|
|
|
|
switch -- $tag {
|
|
supercard {
|
|
set start [supercardStarttag]
|
|
set end [arr endtag]
|
|
lappend defun($module,supercards) [list $start $end]
|
|
|
|
if { $end ne {} } {
|
|
lappend fontlock(begin_supercards) $start
|
|
lappend fontlock(end_supercards) $end
|
|
} else {
|
|
lappend fontlock(open_supercards) $start
|
|
}
|
|
}
|
|
namelist {
|
|
set inside_namelist 1
|
|
lappend fontlock(namelists) $name
|
|
lappend defun($module,namelists) $name
|
|
}
|
|
var - dimension - multidimension {
|
|
if { $inside_namelist } {
|
|
set bare_name [lindex [split $name \(] 0]; # strips "(index)" from variable's name if var is a dimension
|
|
lappend fontlock(vars) $bare_name
|
|
lappend defun($module,vars) $bare_name
|
|
|
|
# is the variable of string-type ?
|
|
set type [arr type]
|
|
if { "$type" eq "CHARACTER" } {
|
|
#set fontlock(stringvar,$bare_name) 1
|
|
set defun($module,stringvar,$bare_name) 1
|
|
}
|
|
}
|
|
}
|
|
keyword {
|
|
lappend fontlock(keywords) $name
|
|
lappend defun($module,cards) $name; # make it easier (glue cards and keywords immediately)
|
|
}
|
|
card {
|
|
set nameless [arr nameless]
|
|
switch -- [string tolower $nameless] {
|
|
1 - true - yes - .true. {
|
|
set name ""
|
|
}
|
|
}
|
|
if { $name != "" } {
|
|
lappend fontlock(cards) $name
|
|
lappend defun($module,cards) $name
|
|
|
|
set flags_txt [getDescendantText $tree $node flag enum]
|
|
set flags_use [getDescendantAttribute $tree $node flag use]
|
|
set flags [regsub -all -- {\|} $flags_txt {}]
|
|
|
|
if { $flags != "" } {
|
|
append fontlock(flags) "$flags "
|
|
#append defun($module,flags) "$flags "
|
|
|
|
if { $flags_use == "optional" } {
|
|
#set fontlock(card_flags,$name) "\{ [string trim $flags_txt { }] \}"
|
|
#set defun($module,card_flags,$name) "\{ [string trim $flags_txt { }] \}"
|
|
set defun($module,card_flags_elist,$name) [flags_to_elist $flags_txt]
|
|
} else {
|
|
#set fontlock(card_flags,$name) [string trim $flags_txt { }]
|
|
#set defun($module,card_flags,$name) [string trim $flags_txt { }]
|
|
set defun($module,card_flags_elist,$name) [flags_to_elist $flags_txt]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if { $tag == "namelist" } {
|
|
set inside_namelist 0
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# Purpose: initialize the machinery for generating qe-modes
|
|
proc ::helpdoc::qe_mode_init {} {
|
|
variable init_qe_mode
|
|
global qe_modes_template_dir
|
|
variable fontlock
|
|
variable defun
|
|
|
|
#catch {unset fontlock}
|
|
#catch {unset defun}
|
|
|
|
set init_qe_mode 1
|
|
|
|
if { ! [info exists qe_modes_template_dir] } {
|
|
# try with this
|
|
puts stderr "
|
|
### variable \"qe_modes_template_dir\" is not defined ... aborting"
|
|
exit 1
|
|
}
|
|
|
|
if { ! [file isdirectory $qe_modes_template_dir] } {
|
|
puts stderr "
|
|
### variable \"qe_modes_template_dir\" points to nonexistent directory: $qe_modes_template_dir
|
|
"
|
|
exit 1
|
|
}
|
|
|
|
# read the schema (and load tag's commands)
|
|
|
|
readSchema
|
|
}
|
|
|
|
|
|
# Purpose: process a given *.def file for the purpose of generating qe-modes
|
|
proc ::helpdoc::qe_mode_process_def {deffile} {
|
|
variable tree
|
|
variable inside_namelist
|
|
variable init_qe_mode
|
|
|
|
if { ! [info exists init_qe_mode] || ! $init_qe_mode } {
|
|
puts stderr "
|
|
### call ::helpdoc::qe_mode_init before the ::helpdoc::qe_mode_process_def
|
|
"
|
|
exit 1
|
|
}
|
|
|
|
set inside_namelist 0
|
|
|
|
# read the deffile
|
|
|
|
puts "\n\n***\n*** Parsing definition file: $deffile\n***\n"
|
|
namespace eval tag [list source $deffile]
|
|
puts ""
|
|
|
|
# walk through the $deffile and extract the info we need (i.e. names of namelists, variables, cards, and flags)
|
|
|
|
$tree walkproc root -order both helpdoc::getFontlockKeys
|
|
}
|
|
|
|
|
|
# Purpose: generate requested qe-mode
|
|
proc ::helpdoc::qe_mode_generate {module_list} {
|
|
variable fontlock
|
|
variable defun
|
|
variable opt
|
|
global qe_modes_template_dir
|
|
# load the variables needed by $opt(template), e.g., qe-mode.el.tcl
|
|
|
|
set mode [string tolower $opt(mode)]
|
|
|
|
if { $opt(modename) eq {} } {
|
|
set modeName QE-$mode.x
|
|
} else {
|
|
set modeName $opt(modename)
|
|
}
|
|
|
|
# closed supercards, i.e., with starttag & endtag
|
|
set sc_l [concat [value_of fontlock(begin_supercards)] [value_of fontlock(end_supercards)]]
|
|
set closed_supercards [quote_list [lsort -unique $sc_l]]
|
|
|
|
# open supercards, i.e., with only starttag
|
|
set open_supercards [quote_list [lsort -unique [value_of fontlock(open_supercards)]]]
|
|
|
|
# cards & flags, namelists & vars
|
|
set cards_l [concat [value_of fontlock(keywords)] [value_of fontlock(cards)]]
|
|
#
|
|
# N.B: if there are no cards, the auto-indentation will not work in emacs;
|
|
# Workaround: create a dummy __NO-CARDS card
|
|
if { $cards_l == "" } {
|
|
set cards_l "__NO-CARDS"
|
|
}
|
|
set cards [quote_list [lsort -unique $cards_l]]
|
|
|
|
set flags [quote_list [lsort -unique [value_of fontlock(flags)]]]
|
|
set namelists [quote_list [lsort -unique [value_of fontlock(namelists)]] $opt(nmlprefix)]
|
|
set vars [quote_list [lsort -unique [value_of fontlock(vars)]]]
|
|
set cmds [quote_list [lsort -unique [value_of opt(cmds)]]]
|
|
#set namelists [quote_list [lsort -nocase -unique [value_of fontlock(namelists)]] $opt(nmlprefix)]
|
|
#set vars [quote_list [lsort -nocase -unique [value_of fontlock(vars)]]]
|
|
#set cmds [quote_list [lsort -nocase -unique [value_of opt(cmds)]]]
|
|
|
|
# PWTK uses uppercase namelist and card names !!!
|
|
if { $opt(mode) == "pwtk" } {
|
|
set namelists [string toupper $namelists]
|
|
set cards [string toupper $cards]
|
|
|
|
# filter-out cmds that already exists in cards
|
|
set newL {}
|
|
foreach cmd $cmds {
|
|
if { [lsearch $cards $cmd] < 0 && [lsearch $namelists $cmd] < 0 } {
|
|
lappend newL $cmd
|
|
}
|
|
}
|
|
set cmds [quote_list $newL]
|
|
}
|
|
|
|
# load the templates
|
|
|
|
set qe_template [tclu::readFile [file join $qe_modes_template_dir $opt(template)]]; # default for opt(template) = qe-mode.el.tcl
|
|
|
|
set header_template [tclu::readFile [file join $qe_modes_template_dir header.el.tcl]]
|
|
set namelist_template [tclu::readFile [file join $qe_modes_template_dir namelist.el.tcl]]
|
|
set var_template [tclu::readFile [file join $qe_modes_template_dir var.el.tcl]]
|
|
set stringvar_template [tclu::readFile [file join $qe_modes_template_dir stringvar.el.tcl]]
|
|
set card_template [tclu::readFile [file join $qe_modes_template_dir card.el.tcl]]
|
|
set card_noflags_template [tclu::readFile [file join $qe_modes_template_dir card-noflags.el.tcl]]
|
|
|
|
set closed_supercard_template [tclu::readFile [file join $qe_modes_template_dir supercard.el.tcl]]
|
|
set open_supercard_template [tclu::readFile [file join $qe_modes_template_dir supercard-open.el.tcl]]
|
|
|
|
# substitute the Tcl variables inside the qe-mode.el.tcl and write the resulting content
|
|
|
|
set file $mode-mode.el
|
|
puts "
|
|
writing Emacs major-mode file : $file
|
|
"
|
|
set header [subst -nocommands -nobackslashes $header_template]
|
|
tclu::writeFile $file [subst -nocommands -nobackslashes $qe_template]
|
|
|
|
# are we done ?
|
|
|
|
if { ! $opt(funcs) } {
|
|
# qe-mode function generation was not requested, we are done
|
|
return
|
|
}
|
|
|
|
########################################################################
|
|
# make utility functions for each module in $Module_list
|
|
|
|
set utility_functions ""
|
|
|
|
puts "list-of-modules = $module_list\n"
|
|
|
|
# create $module-insert-template functions for all modules for which the $module.in file exists
|
|
|
|
foreach module $module_list {
|
|
|
|
set in [file join $qe_modes_template_dir $module.in]
|
|
|
|
if { [file exists $in] } {
|
|
set template [tclu::readFile $in]
|
|
set insert_template [tclu::readFile [file join $qe_modes_template_dir insert-template.el.tcl]]
|
|
|
|
if { $utility_functions eq "" } {
|
|
set utility_functions "
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; utility functions ...
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
"
|
|
}
|
|
append utility_functions [subst -nocommands -nobackslashes $insert_template]\n\n
|
|
}
|
|
}
|
|
|
|
# make keyword functions for this $mode
|
|
|
|
set keyword_functions ""
|
|
|
|
foreach module $module_list {
|
|
|
|
##################################################
|
|
# create elisp functions for each namelist
|
|
if { [value_of defun($module,namelists)] ne "" } {
|
|
|
|
append keyword_functions "
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; $module- namelists functions ...
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
"
|
|
set module_nmls [lsort -nocase -unique [value_of defun($module,namelists)]]
|
|
|
|
foreach nml $module_nmls {
|
|
set namelist "$opt(nmlprefix)[string toupper [string trimleft $nml &]]"
|
|
set namelist_uc [string toupper [string trimleft $nml &]]
|
|
append keyword_functions [subst -nocommands -nobackslashes $namelist_template]\n\n
|
|
}
|
|
}
|
|
|
|
##################################################
|
|
# create elisp functions for each namelist's variable
|
|
|
|
if { [value_of defun($module,vars)] ne "" } {
|
|
|
|
append keyword_functions "
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; $module- namelist's variables functions ...
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
"
|
|
set module_vars [lsort -nocase -unique [value_of defun($module,vars)]]
|
|
|
|
foreach var $module_vars {
|
|
|
|
set var_lc [string tolower $var]
|
|
|
|
# check if var is of string type
|
|
|
|
if { [info exists defun($module,stringvar,$var)] } {
|
|
|
|
set read_cmd read-string
|
|
|
|
if { [string match {*dir} $var_lc] } {
|
|
|
|
# variable probably want a directory name
|
|
set read_cmd read-directory-name
|
|
|
|
} elseif { [string match {*file*} $var_lc] } {
|
|
|
|
# variable probably want a filename name
|
|
set read_cmd read-file-name
|
|
}
|
|
append keyword_functions [subst -nocommands -nobackslashes $stringvar_template]\n\n
|
|
|
|
} else {
|
|
|
|
append keyword_functions [subst -nocommands -nobackslashes $var_template]\n\n
|
|
}
|
|
}
|
|
}
|
|
|
|
##################################################
|
|
# create elisp functions for each supercard
|
|
|
|
if { [value_of defun($module,supercards)] ne "" } {
|
|
|
|
append keyword_functions "
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; $module- supercards functions ...
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
"
|
|
foreach start_end [lsort -unique $defun($module,supercards)] {
|
|
|
|
set starttag [lindex $start_end 0]
|
|
set endtag [lindex $start_end 1]
|
|
|
|
set supercard_uc [string toupper $starttag]
|
|
|
|
if { $endtag ne {} } {
|
|
# it's a closed supercard
|
|
append keyword_functions [subst -nocommands -nobackslashes $closed_supercard_template]\n\n
|
|
} else {
|
|
# it's an open supercard
|
|
append keyword_functions [subst -nocommands -nobackslashes $open_supercard_template]\n\n
|
|
}
|
|
}
|
|
}
|
|
|
|
##################################################
|
|
# create elisp functions for each card
|
|
|
|
if { [value_of defun($module,cards)] ne "" } {
|
|
|
|
append keyword_functions "
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; $module- cards functions ...
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
"
|
|
set module_cards [lsort -unique $defun($module,cards)]
|
|
|
|
foreach card $module_cards {
|
|
|
|
set card_uc [string toupper $card]
|
|
set card_lc [string tolower $card]
|
|
|
|
#if { [info exists defun($module,card_flags,$card)] } {}
|
|
if { [info exists defun($module,card_flags_elist,$card)] } {
|
|
# it's a card with flags
|
|
|
|
#set card_flags $defun($module,card_flags,$card)
|
|
set card_flags_elist $defun($module,card_flags_elist,$card)
|
|
append keyword_functions [subst -nocommands -nobackslashes $card_template]\n\n
|
|
} else {
|
|
# it's a flagless card
|
|
|
|
append keyword_functions [subst -nocommands -nobackslashes $card_noflags_template]\n\n
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
set qe_func_template [tclu::readFile [file join $qe_modes_template_dir qe-funcs.el.tcl]]
|
|
|
|
set file qe-funcs.el
|
|
puts "
|
|
writing function file : $file
|
|
"
|
|
set header [subst -nocommands -nobackslashes $header_template]
|
|
tclu::writeFile $file [subst -nocommands -nobackslashes $qe_func_template]
|
|
}
|
|
|
|
|
|
proc ::helpdoc::qe_master_generate {deffile_list} {
|
|
variable opt
|
|
global qe_modes_template_dir
|
|
|
|
if { "$opt(mode)" ne "qe" } {
|
|
puts stderr "
|
|
ERROR: so far master mode file can be generated only for mode = qe
|
|
"
|
|
exit 1
|
|
}
|
|
|
|
puts "pwd = [pwd]
|
|
"
|
|
set header_template [tclu::readFile [file join $qe_modes_template_dir header.el.tcl]]
|
|
set master_template [tclu::readFile [file join $qe_modes_template_dir $opt(mode)-modes.el.tcl]]
|
|
set specific_template [tclu::readFile [file join $qe_modes_template_dir autoload-specific.el.tcl]]
|
|
|
|
set autoload_specific_modes ""
|
|
|
|
foreach deffile $deffile_list {
|
|
|
|
set module [modulename_from_defname $deffile]
|
|
|
|
switch -exact -- $module {
|
|
atomic {
|
|
set prog ld1.x
|
|
}
|
|
default {
|
|
set prog $module.x
|
|
}
|
|
}
|
|
|
|
puts "mode file = $module-mode.el"
|
|
|
|
if { [file exists $module-mode.el] } {
|
|
|
|
# autolad only for those modules that have the specific mode defined
|
|
|
|
append autoload_specific_modes [subst -nocommands -nobackslashes $specific_template]\n
|
|
}
|
|
}
|
|
set file $opt(mode)-modes.el
|
|
puts "
|
|
|
|
writing master mode file : $file
|
|
"
|
|
set header [subst -nocommands -nobackslashes $header_template]
|
|
tclu::writeFile $opt(mode)-modes.el [subst -nocommands -nobackslashes $master_template]
|
|
}
|