7 people like it.

Line Counter for FS/FSX files

Simple (and inaccurate) command line LOC counter mainly for .fs and .fsx files. Extended from: http://www.fssnip.net/b6/title/How-many-lines-of-code-does-your-project-contain Searches current directory and subdirectories (can be changed to only search current dir). Can be changed to whatever filetype is needed. Can be either run as a script (with fsi) or compiled (with fsc).

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
71: 
72: 
73: 
74: 
75: 
76: 
77: 
78: 
79: 
80: 
81: 
82: 
83: 
84: 
85: 
86: 
87: 
88: 
89: 
90: 
91: 
open System
open System.IO

type Count =
    { LOC:int
      comments:int
      emptyLines:int }

/// Add or remove the file extensions you want.
/// Set to both .fs and .fsx files by default.
let fileExtentions =
    ["fs";"fsx"]
    |> Seq.map (fun s -> "*." + s)

let printCount count =
    printfn "Total LOC: %A" count.LOC
    printfn "Total comment lines: %A" count.comments
    printfn "Total empty lines: %A" count.emptyLines
    printfn "Total LOC + comments: %A" (count.LOC + count.comments)
    printfn "Total lines: %A" (count.LOC + count.comments + count.emptyLines)

let printFileList fileList =
    printfn "Total files counted: %A" (Seq.length fileList)
    printfn "List of files counted:"
    fileList
    |> Seq.iter (printfn "  %s")

let getFiles path wildcards recurse =
    wildcards
    |> Seq.map (fun wildcard ->
        Directory.EnumerateFiles(
            path, 
            wildcard, 
            if recurse then 
                SearchOption.AllDirectories 
            else 
                SearchOption.TopDirectoryOnly
        )
    )
    |> Seq.concat

let lineCount file =
    let isEmpty (line:string) = 
        line.Trim() = ""

    let isComment (line:string) = 
        line.Trim()
        |> fun s ->
        s.StartsWith("//") 
        || s.StartsWith("(*")
        || s.EndsWith("*)")

    let isCode (line:string) = 
        not (isEmpty line) && not (isComment line)

    let getNumLines lineType file =
        File.ReadAllLines file 
        |> Seq.filter lineType
        |> Seq.length

    let LOC = getNumLines isCode file
    let comments = getNumLines isComment file
    let emptyLines = getNumLines isEmpty file
    //return
    {LOC=LOC;comments=comments;emptyLines=emptyLines}

let countLines files =
    files
    |> Seq.map lineCount
    |> Seq.reduce(fun acc elem ->
        { LOC = acc.LOC + elem.LOC
          comments = acc.comments + elem.comments
          emptyLines = acc.emptyLines + elem.emptyLines })

let runCounter fileType =
    let files = getFiles Environment.CurrentDirectory fileType true
    printFileList files
    countLines files
    |> printCount
    printfn "Hit enter to continue..."
    stdin.ReadLine()
    |> ignore

#if COMPILED
[<EntryPoint>]
let main _ =
    runCounter fileExtentions
    0
#else
runCounter fileExtentions
#endif
namespace System
namespace System.IO
type Count =
  {LOC: int;
   comments: int;
   emptyLines: int;}

Full name: Script.Count
Count.LOC: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Count.comments: int
Count.emptyLines: int
val fileExtentions : seq<string>

Full name: Script.fileExtentions


 Add or remove the file extensions you want.
 Set to both .fs and .fsx files by default.
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val s : string
val printCount : count:Count -> unit

Full name: Script.printCount
val count : Count
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val printFileList : fileList:seq<string> -> unit

Full name: Script.printFileList
val fileList : seq<string>
val length : source:seq<'T> -> int

Full name: Microsoft.FSharp.Collections.Seq.length
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
val getFiles : path:string -> wildcards:seq<string> -> recurse:bool -> seq<string>

Full name: Script.getFiles
val path : string
val wildcards : seq<string>
val recurse : bool
val wildcard : string
type Directory =
  static member CreateDirectory : path:string -> DirectoryInfo + 1 overload
  static member Delete : path:string -> unit + 1 overload
  static member EnumerateDirectories : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFileSystemEntries : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFiles : path:string -> IEnumerable<string> + 2 overloads
  static member Exists : path:string -> bool
  static member GetAccessControl : path:string -> DirectorySecurity + 1 overload
  static member GetCreationTime : path:string -> DateTime
  static member GetCreationTimeUtc : path:string -> DateTime
  static member GetCurrentDirectory : unit -> string
  ...

Full name: System.IO.Directory
Directory.EnumerateFiles(path: string) : Collections.Generic.IEnumerable<string>
Directory.EnumerateFiles(path: string, searchPattern: string) : Collections.Generic.IEnumerable<string>
Directory.EnumerateFiles(path: string, searchPattern: string, searchOption: SearchOption) : Collections.Generic.IEnumerable<string>
type SearchOption =
  | TopDirectoryOnly = 0
  | AllDirectories = 1

Full name: System.IO.SearchOption
field SearchOption.AllDirectories = 1
field SearchOption.TopDirectoryOnly = 0
val concat : sources:seq<#seq<'T>> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.concat
val lineCount : file:string -> Count

Full name: Script.lineCount
val file : string
val isEmpty : (string -> bool)
val line : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
String.Trim() : string
String.Trim([<ParamArray>] trimChars: char []) : string
val isComment : (string -> bool)
String.StartsWith(value: string) : bool
String.StartsWith(value: string, comparisonType: StringComparison) : bool
String.StartsWith(value: string, ignoreCase: bool, culture: Globalization.CultureInfo) : bool
String.EndsWith(value: string) : bool
String.EndsWith(value: string, comparisonType: StringComparison) : bool
String.EndsWith(value: string, ignoreCase: bool, culture: Globalization.CultureInfo) : bool
val isCode : (string -> bool)
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
val getNumLines : ((string -> bool) -> string -> int)
val lineType : (string -> bool)
type File =
  static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
  static member AppendAllText : path:string * contents:string -> unit + 1 overload
  static member AppendText : path:string -> StreamWriter
  static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
  static member Create : path:string -> FileStream + 3 overloads
  static member CreateText : path:string -> StreamWriter
  static member Decrypt : path:string -> unit
  static member Delete : path:string -> unit
  static member Encrypt : path:string -> unit
  static member Exists : path:string -> bool
  ...

Full name: System.IO.File
File.ReadAllLines(path: string) : string []
File.ReadAllLines(path: string, encoding: Text.Encoding) : string []
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val LOC : int
val comments : int
val emptyLines : int
val countLines : files:seq<string> -> Count

Full name: Script.countLines
val files : seq<string>
val reduce : reduction:('T -> 'T -> 'T) -> source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.reduce
val acc : Count
val elem : Count
val runCounter : fileType:seq<string> -> unit

Full name: Script.runCounter
val fileType : seq<string>
type Environment =
  static member CommandLine : string
  static member CurrentDirectory : string with get, set
  static member Exit : exitCode:int -> unit
  static member ExitCode : int with get, set
  static member ExpandEnvironmentVariables : name:string -> string
  static member FailFast : message:string -> unit + 1 overload
  static member GetCommandLineArgs : unit -> string[]
  static member GetEnvironmentVariable : variable:string -> string + 1 overload
  static member GetEnvironmentVariables : unit -> IDictionary + 1 overload
  static member GetFolderPath : folder:SpecialFolder -> string + 1 overload
  ...
  nested type SpecialFolder
  nested type SpecialFolderOption

Full name: System.Environment
property Environment.CurrentDirectory: string
val stdin<'T> : TextReader

Full name: Microsoft.FSharp.Core.Operators.stdin
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
Raw view Test code New version

More information

Link:http://fssnip.net/7W4
Posted:5 years ago
Author:LSM07
Tags: analyzers , line count