Skip to content
Browse files

Added support for configuration files

Configuration files use the same format as the --config string (except that commas can
be replaced by newlines), and can be placed in ~/.ocp/ocp-indent.conf, or in a .ocp-indent
file in any parent directory. This provides a convenient way to have per-project setups
that can be easily shared by any contributor.

Setting the ocp-indent-config variable in emacs-customise is now deprecated.
  • Loading branch information...
1 parent 1dbfe61 commit d63ab6f56912fde68140fa594020d335b50c8ae2 @AltGr AltGr committed Mar 19, 2013
Showing with 196 additions and 28 deletions.
  1. +10 −0 .ocp-indent
  2. +14 −7 src/indentArgs.ml
  3. +1 −1 src/indentArgs.mli
  4. +106 −12 src/indentConfig.ml
  5. +24 −0 src/indentConfig.mli
  6. +17 −4 src/indentMain.ml
  7. +17 −0 src/util.ml
  8. +1 −0 tests/.ocp-indent
  9. +3 −3 tests/failing.html
  10. +3 −1 tools/ocp-indent.el
View
10 .ocp-indent
@@ -0,0 +1,10 @@
+# This is an example of configuration file; any file below this directory will
+# inherit from it, unless another conf-file is found.
+base = 2
+type = 2
+in = 0
+with = 0
+strict_with = never
+match_clause = 4 # this is non-default
+strict_comments = false
+align_params = auto
View
21 src/indentArgs.ml
@@ -28,7 +28,9 @@ let debug = ref false
let file_out = ref None
let lines = ref (None, None)
let numeric = ref false
-let indent_config = ref IndentConfig.default
+(* [indent_config] Stores the config strings, because different files may have
+ different defaults if located in different directories *)
+let indent_config = ref []
let inplace = ref false
type input = InChannel of in_channel
@@ -65,12 +67,12 @@ let set_lines str =
let set_indent s =
if s = "help" then (print_endline IndentConfig.help; exit 0) else
try
- indent_config := IndentConfig.update_from_string !indent_config s
+ (* just checking syntax *)
+ ignore (IndentConfig.update_from_string IndentConfig.default s);
+ indent_config := s :: !indent_config
with
| Invalid_argument s ->
- error "Bad --config parameter %S.\n%s" s IndentConfig.help
- | Failure _ ->
- error "Bad --config value %S.\n%s" s IndentConfig.help
+ error "Bad --config parameter:\n%s\n\n%s" s IndentConfig.help
let set_output s = match !file_out with
| None -> file_out := Some s
@@ -82,6 +84,11 @@ let syntax_ext name =
error "Unknown syntax extension %S. Available choices are %s."
name (String.concat ", " (Approx_lexer.available_extensions ()))
+let print_config () =
+ print_endline
+ (IndentConfig.to_string ~sep:"\n" (IndentConfig.local_default ()));
+ exit 0
+
let arg_list = Arg.align [
"--config" , Arg.String set_indent, " ";
"-c" , Arg.String set_indent, "var=value[,var=value...] \
@@ -99,6 +106,8 @@ let arg_list = Arg.align [
"--output" , Arg.String set_output, " ";
"-o" , Arg.String set_output, "file Save output \
to file";
+ "--print-config",
+ Arg.Unit print_config, " Print the local configuration to stdout";
"--syntax" , Arg.String syntax_ext, Printf.sprintf "<%s> Handle keywords \
for the given syntax \
extension"
@@ -118,8 +127,6 @@ let parse () =
Arg.parse arg_list arg_anon usage;
let f = match !files with
| [] -> [InChannel stdin]
- (* | _::_::_ when not !inplace -> *)
- (* error "Multiple files can only be supplied with --inplace." *)
| f -> List.rev f
in
files := f;
View
2 src/indentArgs.mli
@@ -17,7 +17,7 @@
val file_out : string option ref
val numeric: bool ref
-val indent_config: IndentConfig.t ref
+val indent_config: string list ref
val debug: bool ref
val inplace : bool ref
View
118 src/indentConfig.ml
@@ -65,6 +65,25 @@ let string_of_threechoices = function
| Never -> "never"
| Auto -> "auto"
+let to_string ?(sep=",") indent =
+ Printf.sprintf
+ "base=%d%s\
+ type=%d%s\
+ in=%d%s\
+ with=%d%s\
+ strict_with=%s%s\
+ match_clause=%d%s\
+ strict_comments=%b%s\
+ align_params=%s"
+ indent.i_base sep
+ indent.i_type sep
+ indent.i_in sep
+ indent.i_with sep
+ (string_of_threechoices indent.i_strict_with) sep
+ indent.i_match_clause sep
+ indent.i_strict_comments sep
+ (string_of_threechoices indent.i_align_params)
+
let set t var_name value =
try
match var_name with
@@ -78,7 +97,9 @@ let set t var_name value =
| "match_clause" -> {t with i_match_clause = int_of_string value}
| "strict_comments" -> {t with i_strict_comments = bool_of_string value}
| "align_params" -> {t with i_align_params = threechoices_of_string value}
- | _ -> raise (Invalid_argument var_name)
+ | var_name ->
+ let e = Printf.sprintf "unknown configuration key %S" var_name in
+ raise (Invalid_argument e)
with
| Failure "int_of_string" ->
let e = Printf.sprintf "%s should be an integer, not %S" var_name value in
@@ -99,14 +120,19 @@ let set t var_name value =
let update_from_string indent s =
List.fold_left
- (fun indent s -> match Util.string_split '=' (String.trim s) with
- | [var;value] -> set indent var value
+ (fun indent s -> match Util.string_split '=' s with
+ | [] | [""] -> indent
+ | [var;value] -> set indent (String.trim var) (String.trim value)
| [preset] ->
- (try List.assoc preset presets with
- Not_found -> raise (Invalid_argument preset))
- | _ -> raise (Invalid_argument s))
+ (try List.assoc (String.trim preset) presets with
+ Not_found ->
+ let e = Printf.sprintf "unknown preset %S" preset in
+ raise (Invalid_argument e))
+ | _ ->
+ let e = Printf.sprintf "wrong \"param=value\" pair in %S" s in
+ raise (Invalid_argument e))
indent
- (Util.string_split ',' s)
+ (Util.string_split_chars ",\n" s)
let help =
Printf.sprintf
@@ -144,11 +170,79 @@ let help =
(string_of_threechoices default.i_align_params)
(String.concat ", " (List.map fst presets))
-let default =
+let save t file =
+ try
+ let oc = open_out file in
+ output_string oc (to_string ~sep:"\n" t);
+ output_char oc '\n';
+ true
+ with Sys_error _ ->
+ Printf.eprintf
+ "ocp-indent warning: could not open %S for writing configuration.\n%!"
+ file;
+ false
+
+let load ?(indent=default) file =
try
- update_from_string default (Sys.getenv ("OCP_INDENT_CONFIG"))
+ let ic = open_in file in
+ let contents =
+ let b = Buffer.create 512 in
+ try while true do
+ let s = input_line ic in
+ let n = try String.index s '#' with Not_found -> String.length s in
+ Buffer.add_substring b s 0 n;
+ Buffer.add_char b '\n'
+ done; assert false
+ with End_of_file -> Buffer.contents b
+ in
+ update_from_string indent contents
with
- | Not_found -> default
- | Invalid_argument _ ->
- prerr_endline "Warning: invalid $OCP_INDENT_CONFIG";
+ | Sys_error _ ->
+ Printf.eprintf
+ "ocp-indent warning: could not open %S for reading configuration.\n%!"
+ file;
+ indent
+ | Invalid_argument err ->
+ Printf.eprintf
+ "ocp-indent warning: error in configuration file %S:\n%s\n%!"
+ file err;
default
+
+let conf_file_name = ".ocp-indent"
+
+let rec find_conf_file path =
+ let (/) = Filename.concat in
+ if Sys.file_exists (path / conf_file_name)
+ then Some (path / conf_file_name)
+ else
+ let path =
+ if Filename.is_relative path then Sys.getcwd () / path
+ else path
+ in
+ let parent = Filename.dirname path in
+ if parent <> path then find_conf_file parent
+ else None
+
+let local_default ?(path=Sys.getcwd()) () =
+ let conf = default in
+ let conf =
+ try
+ let (/) = Filename.concat in
+ let f = (Sys.getenv "HOME") / ".ocp" / "ocp-indent.conf" in
+ if Sys.file_exists f then load ~indent:conf f else conf
+ with Not_found -> conf
+ in
+ let conf = match find_conf_file path with
+ | Some c -> load ~indent:conf c
+ | None -> conf
+ in
+ let conf =
+ try update_from_string conf
+ (Sys.getenv ("OCP_INDENT_CONFIG"))
+ with
+ | Not_found -> conf
+ | Invalid_argument _ ->
+ prerr_endline "Warning: invalid $OCP_INDENT_CONFIG";
+ conf
+ in
+ conf
View
24 src/indentConfig.mli
@@ -84,4 +84,28 @@ val help: string
val default: t
+(** String format is [option=value,option2=value,...]. Commas can be replaced
+ by newlines *)
val update_from_string : t -> string -> t
+
+(** sep should be comma or newline if you want to reparse. Comma by default *)
+val to_string : ?sep:string -> t -> string
+
+(** Load from the given filename, optionally updating from the given indent
+ instead of the default one. On error, returns the original indent config
+ unchanged and prints a message to stderr *)
+val load: ?indent:t -> string -> t
+
+(** Save the given indent config to the given filename; returns true on
+ success *)
+val save: t -> string -> bool
+
+(** Looks in given and parent directories for a [.ocp-indent] configuration
+ file *)
+val find_conf_file: string -> string option
+
+(** Returns the local default configuration, obtained from (in order), the
+ built-in [default], the file [~/.ocp/ocp-indent.conf], a file [.ocp-indent]
+ in the current directory or any parent, and the environment variable
+ [OCP_INDENT] *)
+val local_default: ?path:string -> unit -> t
View
21 src/indentMain.ml
@@ -15,7 +15,7 @@
module Args = IndentArgs
-let indent_channel ic out =
+let indent_channel ic config out =
if !Args.inplace && !Args.numeric then
Args.error "--inplace and --numeric are incompatible";
let oc, need_close = match out with
@@ -27,7 +27,7 @@ let indent_channel ic out =
let output = {
IndentPrinter.
debug = !Args.debug;
- config = !Args.indent_config;
+ config = config;
in_lines = Args.in_lines;
indent_empty = Args.indent_empty ();
kind =
@@ -51,8 +51,21 @@ let indent_channel ic out =
let indent_file = function
- | Args.InChannel ic -> indent_channel ic !Args.file_out
+ | Args.InChannel ic ->
+ let config =
+ List.fold_right
+ (fun s conf -> IndentConfig.update_from_string conf s)
+ !Args.indent_config
+ (IndentConfig.local_default ())
+ in
+ indent_channel ic config !Args.file_out
| Args.File path ->
+ let config =
+ List.fold_right
+ (fun s conf -> IndentConfig.update_from_string conf s)
+ !Args.indent_config
+ (IndentConfig.local_default ~path:(Filename.dirname path) ())
+ in
let out, need_move =
if !Args.inplace then
let tmp_file = path ^ ".ocp-indent" in
@@ -62,7 +75,7 @@ let indent_file = function
in
let ic = open_in path in
try
- indent_channel ic out;
+ indent_channel ic config out;
match out, need_move with
| Some src, Some dst -> Sys.rename src dst
| _, _ -> ()
View
17 src/util.ml
@@ -33,6 +33,23 @@ let string_split char str =
in
aux 0
+let string_split_chars chars str =
+ let len = String.length str in
+ let rec split pos =
+ let rec lookup i =
+ if i >= len then raise Not_found
+ else if String.contains chars str.[i] then i
+ else lookup (succ i)
+ in
+ try
+ let i = lookup pos in
+ if i > pos then String.sub str pos (i - pos) :: split (succ i)
+ else split (succ i)
+ with Not_found | Invalid_argument _ ->
+ [ String.sub str pos (len - pos) ]
+ in
+ split 0
+
let is_prefix pfx str =
let pfxlen = String.length pfx in
let rec check i = i >= pfxlen || pfx.[i] = str.[i] && check (i+1) in
View
1 tests/.ocp-indent
@@ -0,0 +1 @@
+normal
View
6 tests/failing.html
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
- <title>Failing tests, ocp-indent version 1.0.2+8 (2013-03-14)</title>
+ <title>Failing tests, ocp-indent version 1.0.2+10 (2013-03-19)</title>
<style>
BODY { font-family: monospace; }
TABLE { border-collapse: collapse; border-spacing: 0px; margin: auto; }
@@ -22,7 +22,7 @@
</style>
</head>
<body>
-<h1>Failing tests, ocp-indent version 1.0.2+8 (2013-03-14)</h1>
+<h1>Failing tests, ocp-indent version 1.0.2+10 (2013-03-19)</h1>
<p>Left is expected result, right shows actual indentation by ocp-indent</p>
<table>
<tr><td width="70%">
@@ -923,6 +923,6 @@
</tr>
</table>
<hr/>
-<i>Generated by <b>diff2html</b> on 2013-03-14 17:57:15</i>
+<i>Generated by <b>diff2html</b> on 2013-03-19 15:32:25</i>
</body>
</html>
View
4 tools/ocp-indent.el
@@ -14,7 +14,9 @@
:group 'ocp-indent :type '(file))
(defcustom ocp-indent-config nil
- "*Ocp-indent config string, as for its --config option"
+ "*Ocp-indent config string, as for its --config option.
+WARNING: DEPRECATED, this will override any user or project
+ocp-indent configuration files"
:group 'ocp-indent
:type '(choice (const nil) (string)))

0 comments on commit d63ab6f

Please sign in to comment.
Something went wrong with that request. Please try again.