;; major mode for editing PFLOTRAN input files ;; by Kris Kuhlman, 2014-2017 ;; references ;; http://ergoemacs.org/emacs/elisp_comment_handling.html ;; http://ergoemacs.org/emacs/elisp_syntax_coloring.html ;; http://www.emacswiki.org/emacs/SampleMode ;; https://www.emacswiki.org/emacs-test/EmacsSyntaxTable ;; to make this work automatically, put the following two lines (uncommented) into your ~/.emacs file ;; and save this file into the specified load path directory ;; (add-to-list 'load-path "~/change/this/to/point/to/elisp/files/") ;; (require 'pflotran-mode) (defvar pflotran-mode-hook nil) (add-to-list 'auto-mode-alist '("\\.in\\'" . pflotran-mode)) ;; command to comment/uncomment text :: convention is to make new comments using "#" syntax (defun pflotran-comment-dwim (arg) "Comment or uncomment current line or region in a smart way. For detail, see `comment-dwim'." (interactive "*P") (require 'newcomment) (let ((comment-start "#") (comment-end "")) (comment-dwim arg))) ;; syntax table (defvar pflotran-syntax-table nil "Syntax table for `pflotran-mode'.") (setq pflotran-syntax-table (let ((synTable (make-syntax-table))) ;; braces are nothing special, put them in word class (not delimiters) ;; but these also don't typically show up in input files (modify-syntax-entry ?[ "w" synTable) (modify-syntax-entry ?] "w" synTable) (modify-syntax-entry ?} "w" synTable) (modify-syntax-entry ?{ "w" synTable) (modify-syntax-entry ?) "w" synTable) (modify-syntax-entry ?( "w" synTable) ;; make underscore and dash part of words too ;;(modify-syntax-entry ?_ "w" synTable) ;;(modify-syntax-entry ?- "w" synTable) ;; recognize "!", "#", or ":" comments in input files ;; these comments continue to the end of the line ;; skip ... noskip is handled below (outside syntax table) (modify-syntax-entry ?# "< b" synTable) (modify-syntax-entry ?! "< b" synTable) (modify-syntax-entry ?: "< b" synTable) (modify-syntax-entry ?\n "> b" synTable) synTable)) ;; define several class of keywords ;; top-level cards which whose contents are indented and take arguments (setq pflotran-toplevel '("CHEMISTRY" "GRID" "GEOMECHANICS_GRID" "GEOMECHANICS_SUBSURFACE_COUPLING" "MODE" "BOUNDARY_CONDITION" "CHARACTERISTIC_CURVES" "CONSTRAINT" "DATASET" "DBASE_FILENAME" "EOS" "FLOW_CONDITION" "GEOMECHANICS_CONDITION" "GEOMECHANICS_BOUNDARY_CONDITION" "FLUID_PROPERTY" "INITIAL_CONDITION" "MATERIAL_PROPERTY" "NEWTON_SOLVER" "REGION" "GEOMECHANICS_REGION" "SOURCE_SINK" "STRATA" "GEOMECHANICS_STRATA" "TIMESTEPPER" "TRANSPORT_CONDITION" "OBSERVATION" "OUTPUT" "GEOMECHANICS_OUTPUT" "DEBUG" "RESTART" "WALLCLOCK_STOP" "SIMULATION" "SUBSURFACE" "GEOMECHANICS" "PRIMARY_SPECIES" "TIME" "GEOMECHANICS_TIME" "END" "/" "END_SUBSURFACE" "END_GEOMECHANICS" "AUXILIARY" "SALINITY" "KLINKENBERG_EFFECT")) ;; second-level cards that directly take arguments (not indented) (setq pflotran-secondlevel '("TYPE" "NXYZ" "BOUNDS" "FILE" "ALPHA" "LAMBDA" "LIQUID_RESIDUAL_SATURATION" "GAS_RESIDUAL_SATURATION" "PHASE" "MAX_CAPILLARY_PRESSURE" "NAME" "FILENAME" "HDF5_DATASET_NAME" "DENSITY" "ENTHALPY" "VISCOSITY" "SOLVER" "PRECONDITIONER" "ATOL" "RTOL" "DTOL" "STOL" "ITOL" "ITOL_UPDATE" "ITOL_SCALED_RESIDUAL" "ITOL_RELATIVE_UPDATE" "MAXIT" "MAXF" "MATRIX_TYPE" "PRECONDITIONER_MATRIX_TYPE" "NO_INFINITY_NORM" "NO_FORCE_ITERATION" "NO_PRINT_CONVERGENCE" "PRINT_DETAILED_CONVERGENCE" "ID" "POROSITY" "PERIODIC" "TORTUOSITY" "TORTUOSITY_POWER" "ROCK_DENSITY" "SPECIFIC_HEAT" "HEAT_CAPACITY" "LONGITUDINAL_DISPERSIVITY" "THERMAL_CONDUCTIVITY_DRY" "THERMAL_CONDUCTIVITY_WET" "PORE_COMPRESSIBILITY" "THERMAL_EXPANSIVITY" "SOIL_COMPRESSIBILITY_FUNCTION" "SOIL_COMPRESSIBILITY" "SOIL_REFERENCE_PRESSURE" "COORDINATE" "COORDINATES" "BLOCK" "LIST" "FACE" "PERMEABILITY_FUNCTION_TYPE" "RESIDUAL_SATURATION" "MATERIAL" "GEOMECHANICS_MATERIAL" "STEADY_STATE" "INITIAL_TIMESTEP_SIZE" "MAXIMUM_TIMESTEP_SIZE" "FINAL_TIME" "NUM_STEPS_AFTER_CUT" "MAX_STEPS" "TS_ACCELERATION" "MAX_TS_CUTS" "CFL_LIMITER" "DT_FACTOR" "INITIALIZE_TO_STEADY_STATE" "RUN_AS_STEADY_STATE" "MAX_PRESSURE_CHANGE" "MAX_TEMPERATURE_CHANGE" "MAX_CONCENTRATION_CHANGE" "MAX_SATURATION_CHANGE" "CONSTRAINT" "CONSTRAINT_LIST" "SCREEN" "PERIODIC_OBSERVATION" "PROC" "RESTART" "WALLCLOCK_STOP" "GRAVITY" "ORIGIN" "PRESSURE" "RATE" "ENERGY_RATE" "WELL" "FLUX" "ENERGY_FLUX" "DATUM" "GRADIENT" "INTERPOLATION" "CONDUCTANCE" "FORMAT" "UNIFORM_VELOCITY" "DIFFUSION_COEFFICIENT" "LIQUID_DIFFUSION_COEFFICIENT" "GAS_DIFFUSION_COEFFICIENT" "MOLE_FRACTION" "SIMULATION_TYPE" "TIME_UNITS" "DATA_UNITS" "EXTERNAL_FILE" "DATABASE" "ACTIVITY_COEFFICIENTS" "RATE_CONSTANT" "SURFACE_AREA_POROSITY_POWER" "SURFACE_AREA_VOL_FRAC_POWER" "PREFACTOR_SPECIES" "ACTIVITY_COEFFICIENTS" "SPECIES" "TIMES" "MAPPING_FILE" "YOUNGS_MODULUS" "POISSONS_RATIO" "BIOT_COEFFICIENT" "THERMAL_EXPANSION_COEFFICIENT" "DISPLACEMENT_X" "DISPLACEMENT_Y" "DISPLACEMENT_Z" "FORCE_X" "FORCE_Y" "FORCE_Z" "CO2_DATABASE" "UNITS" "CONCENTRATION" "IPHASE" "COUPLING_TIMESTEP_SIZE" "NPARAM" "SIGMAZ" "MUZ" "RMAX" "R0" "HALF_LIFE" "RELATIVE_HUMIDITY" "GAS_COMPONENT_FORMULA_WEIGHT" "MAX_CFL")) ;; second-level card that takes indented arguments (setq pflotran-secondlevelargs '("PERMEABILITY" "PROCESS_MODELS" "VARIABLES" "CHECKPOINT" "PERMEABILITY_FUNCTION" "DXYZ" "SUBSURFACE_FLOW" "SUBSURFACE_TRANSPORT" "PRIMARY_SPECIES" "SECONDARY_SPECIES" "GAS_SPECIES" "ACTIVE_GAS_SPECIES" "MINERALS" "MINERAL_KINETICS" "GENERAL_REACTION" "RADIOACTIVE_DECAY_REACTION" "CONCENTRATIONS" "TRANSPORT_CONDITION" "OBSERVATION" "OUTPUT" "FLOW_CONDITION" "FLUID_PROPERTY" "INITIAL_CONDITION" "LINEAR_SOLVER" "MATERIAL_PROPERTY" "OPTIONS" "GEOMECHANICS_MATERIAL_PROPERTY" "MASS_BALANCE_FILE" "OBSERVATION_FILE" "SNAPSHOT_FILE" "SATURATION_FUNCTION")) ;; third-level cards (setq pflotran-thirdlevel '("PERM_ISO" "PERM_X" "PERM_Y" "PERM_Z" "VERTICAL_ANISOTOPY_FACTOR" "PERMEABILITY_POWER" "TIMESTEP" "UPDATE_POROSITY" "UPDATE_TORTUOSITY" "TWO_WAY_COUPLED" "REACTION" "FORWARD_RATE" "BACKWARD_RATE")) ;; flags (things that don't take arguments) (setq pflotran-flags '("TH" "GLOBAL_IMPLICIT" "RICHARDS" "MPHASE" "GENERAL" "IMS" "IMMIS" "THS" "SMOOTH" "ANISOTROPIC" "ISOTROPIC" "AIJ" "BAIJ" "HYPRESTRUCT" "VELOCITY" "VELOCITY_AT_CENTER" "VELOCITY_AT_FACE" "NO_PRINT_INITIAL" "NO_PRINT_FINAL" "POROSITY" "PERMEABILITY" "PROCESSOR_ID" "PRINT_SOLUTION" "PRINT_RESIDUAL" "PRINT_JACOBIAN" "PRINT_JACOBIAN_DETAILED" "PRINT_JACOBIAN_NORM" "PRINT_COUPLERS" "PRINT_NUMERICAL_DERIVATIVES" "WAYPOINTS" "BINARY_FORMAT" "INVERT_Z" "STRUCTURED" "CYLINDRICAL" "UNSTRUCTURED" "UNSTRUCTURED_EXPLICIT" "DIRICHLET" "DIRICHLET_ZERO_GRADIENT" "HYDROSTATIC" "SEEPAGE" "CONDUCTANCE" "MASS_RATE" "VOLMETRIC_RATE" "SCALED_MASS_RATE" "SCALED_VOLUMETRIC_RATE" "NEUMANN" "CYCLIC" "SYNC_TIMESTEP_WITH_UPDATE" "NORTH" "SOUTH" "EAST" "WEST" "TOP" "BOTTOM" "HDF5" "TECPLOT" "SINGLE_FILE" "MULTIPLE_FILES" "INACTIVE" "LOG_FORMULATION" "MATERIAL_ID" "CONSTANT" "EXPONENTIAL" "LIQUID" "GAS" "ISOTHERMAL" "GEOMECHANICS_SUBSURFACE" "POINT" "BLOCK" "LIQUID_PRESSURE" "LIQUID_SATURATION" "LIQUID_DENSITY" "GAS_SATURATION" "GAS_PRESSURE" "GAS_DENSITY" "GAS_MOBILITY" "TEMPERATURE" "THERMODYNAMIC_STATE" "MAXIMUM_PRESSURE" "LIQUID_DENSITY" "LIQUID_MOBILITY" "LIQUID_HEAD" "LIQUID_ENERGY" "GAS_ENERGY" "OIL_PRESSURE" "OIL_SATURATION" "OIL_DENSITY" "OIL_MOBILITY" "OIL_ENERGY" "LIQUID_MOLE_FRACTIONS" "GAS_MOLE_FRACTIONS" "LIQUID_MASS_FRACTIONS" "GAS_MASS_FRACTIONS" "AIR_PRESSURE" "CAPILLARY_PRESSURE" "VAPOR_PRESSURE" "SATURATION_PRESSURE" "RESIDUAL" "MINERAL_POROSITY" "EFFECTIVE_POROSITY" "PROCESS_ID" "VOLUME" "MATERIAL_ID_KLUDGE_FOR_VISIT" "LINEAR" "STEP" "MUALEM_VG_GAS" "MUALEM_VG_LIQ" "VAN_GENUCHTEN" "BROOKS_COREY" "MUALEM" "BURDINE" "MUALEM_VG_GAS" "BURDINE_BC_GAS" "MODIFIED_KOSUGI" "MODIFIED_KOSUGI_GAS" "MODIFIED_KOSUGI_LIQ" "INPUT_RECORD_FILE" "TEST" "ANALYTICAL_DERIVATIVES")) ;; standout stuff (deprecated?) (setq pflotran-RED '("DEFAULT" "SATURATION_FUNCTION_TYPE")) ;; units (setq pflotran-units '("sec" "min" "hr" "day" "yr" "kg/s" "kg/yr" "W/s" "W/yr" "K" "C" "M" "mol/L" "KJ/mol" "m" "mm" "cm" "meter" "km" "m^3/day" "Pa" "MW" "N")) ;; create the regex string for each class of keywords ('words splits on _) (setq pflotran-toplevel-regexp (regexp-opt pflotran-toplevel 'symbols)) (setq pflotran-secondlevel-regexp (regexp-opt pflotran-secondlevel 'symbols)) (setq pflotran-secondlevelargs-regexp (regexp-opt pflotran-secondlevelargs 'symbols)) (setq pflotran-thirdlevel-regexp (regexp-opt pflotran-thirdlevel 'symbols)) (setq pflotran-flags-regexp (regexp-opt pflotran-flags 'symbols)) (setq pflotran-RED-regexp (regexp-opt pflotran-RED 'symbols)) (setq pflotran-units-regexp (regexp-opt pflotran-units 'symbols)) ;; clear memory (setq pflotran-toplevel nil) (setq pflotran-secondlevel nil) (setq pflotran-secondlevelargs nil) (setq pflotran-thirdlevel nil) (setq pflotran-flags nil) (setq pflotran-RED nil) (setq pflotran-units nil) ;; create the list for font-lock. ;; each class of keyword is given a particular face ;; ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Faces-for-Font-Lock.html ;; font-lock-warning-face X (RED) ;; font-lock-function-name-face X ;; font-lock-variable-name-face X ;; font-lock-keyword-face X ;; font-lock-comment-face X ;; font-lock-comment-delimiter-face ;; font-lock-type-face X ;; font-lock-constant-face (RED) ;; font-lock-builtin-face X ;; font-lock-preprocessor-face ;; font-lock-string-face X ;; font-lock-doc-face ;; font-lock-negation-char-face ;; (setq pflotran-font-lock-keywords `((,pflotran-toplevel-regexp . font-lock-function-name-face) (,pflotran-secondlevel-regexp . font-lock-variable-name-face) (,pflotran-secondlevelargs-regexp . font-lock-keyword-face) (,pflotran-thirdlevel-regexp . font-lock-type-face) (,pflotran-flags-regexp . font-lock-builtin-face) (,pflotran-RED-regexp . font-lock-warning-face) (,pflotran-units-regexp . font-lock-string-face) ) ) ;; define the mode (define-derived-mode pflotran-mode fundamental-mode "pflotran mode" "Major mode for editing PFLOTRAN input files" :syntax-table pflotran-syntax-table ;; code for syntax highlighting (setq font-lock-defaults '((pflotran-font-lock-keywords))) (setq mode-name "PFLOTRAN") ;; http://emacs.stackexchange.com/questions/20434/setting-comment-face-in-major-mode-on-multi-line-word-delimited-comments ;; handle skip ... noskip comment-delimiter pair differently (setq-local syntax-propertize-function (syntax-propertize-rules ("\\_<\\(s\\)kip\\_>" (1 "<")) ("\\_" (1 ">")))) (define-key pflotran-mode-map [remap comment-dwim] 'pflotran-comment-dwim) ) (provide 'pflotran-mode)